diff -u --recursive --new-file v2.3.47/linux/CREDITS linux/CREDITS --- v2.3.47/linux/CREDITS Sun Feb 20 21:12:38 2000 +++ linux/CREDITS Fri Feb 25 10:26:41 2000 @@ -1259,6 +1259,12 @@ E: ajk@iehk.rwth-aachen.de D: 6pack driver for AX.25 +N: Harald Koerfgen +E: harald@unix-ag.org +D: DECstation port +S: D-50931 Koeln +S: Germany + N: Willy Konynenberg E: willy@xos.nl W: http://www.xos.nl/ @@ -1505,15 +1511,17 @@ S: USA N: Martin Mares -E: mj@atrey.karlin.mff.cuni.cz +E: mj@suse.cz +E: mj@ucw.cz W: http://atrey.karlin.mff.cuni.cz/~mj/ D: BIOS video mode handling code D: MOXA C-218 serial board driver D: Network autoconfiguration +D: PCI subsystem D: Random kernel hacking S: Kankovskeho 1241 S: 182 00 Praha 8 -S: Czech Republic +S: Czech Republic N: John A. Martin E: jam@acm.org @@ -2017,6 +2025,14 @@ S: Canberra ACT 2601 S: Australia +N: Sampo Saaristo +E: sambo@cs.tut.fi +D: Co-author of Multi-Protocol Over ATM (MPOA) +S: Tampere University of Technology / Telecom lab +S: Hermiankatu 12C +S: FIN-33720 Tampere +S: Finland + N: Thomas Sailer E: sailer@ife.ee.ethz.ch E: HB9JNX@HB9W.CHE.EU (packet radio) @@ -2399,6 +2415,14 @@ S: Nashua, New Hampshire 03062 S: USA +N: Heikki Vatiainen +E: hessu@cs.tut.fi +D: Co-author of Multi-Protocol Over ATM (MPOA), some LANE hacks +S: Tampere University of Technology / Telecom lab +S: Hermiankatu 12C +S: FIN-33720 Tampere +S: Finland + N: Andrew Veliath E: andrewtv@usa.net D: Turtle Beach MultiSound sound driver @@ -2425,6 +2449,14 @@ S: 1098 VA Amsterdam S: The Netherlands +N: Peter Shaobo Wang +E: pwang@mmdcorp.com +W: http://www.mmdcorp.com/pw/linux +D: Driver for Interphase ATM (i)Chip SAR adapter card family (x575, x525, x531). +S: 1513 Brewster Dr. +S: Carrollton, TX 75010 +S: USA + N: Tim Waugh E: tim@cyberelk.demon.co.uk D: Co-architect of the parallel-port sharing system @@ -2463,6 +2495,14 @@ S: Computer Science Division S: UC Berkeley S: Berkeley, CA 94720-1776 +S: USA + +N: Bill Wendling +E: wendling@ganymede.isdn.uiuc.edu +W: http://www.ncsa.uiuc.edu/~wendling/ +D: Various random hacks. Mostly on poll/select logic. +S: 605 E. Springfield Ave. +S: Champaign, IL 61820 S: USA N: Mike Westall diff -u --recursive --new-file v2.3.47/linux/Documentation/Changes linux/Documentation/Changes --- v2.3.47/linux/Documentation/Changes Tue Jan 11 22:31:35 2000 +++ linux/Documentation/Changes Mon Feb 21 11:04:30 2000 @@ -33,7 +33,7 @@ Also, don't forget http://www.linuxhq.com/ for all your Linux kernel needs. -Last updated: March 16, 1999 +Last updated: Feb 21, 2000 Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu). Current Minimal Requirements @@ -512,6 +512,12 @@ Older isdn4k-utils versions don't support EXTRAVERSION into kernel version string. +Logical Volume Manager +====================== +Since 2.3.47 the kernel contains the Logical Volume Manager aka LVM. To use it, +you need to install the LVM tools. More information can be found at the home page +of the LVM project at http://linux.msede.com/lvm/. + Where to get the files ********************** @@ -751,9 +757,9 @@ PCI utils ========= -The 2.0 release: -ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-2.0.tar.gz -ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-2.0.tar.gz +The 2.1.5 release: +ftp://atrey.karlin.mff.cuni.cz/pub/linux/pci/pciutils-2.1.5.tar.gz +ftp://metalab.unc.edu/pub/Linux/hardware/pciutils-2.1.5.tar.gz Powertweak ========== @@ -795,8 +801,16 @@ ISDN4Linux ========== + The v3.1beta7 release: ftp://ftp.isdn4linux.de/pub/isdn4linux/utils/testing/isdn4k-utils.v3.1beta7.tar.gz + +Logical Volume Manager +====================== + +The 0.7 release: +ftp://linux.msede.com/lvm/v0.7/lvm_0.7.tar.gz + Other Info ========== diff -u --recursive --new-file v2.3.47/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.47/linux/Documentation/Configure.help Sun Feb 20 21:12:38 2000 +++ linux/Documentation/Configure.help Sat Feb 26 20:32:12 2000 @@ -323,27 +323,31 @@ Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support CONFIG_BLK_DEV_IDE If you say Y here, you will use the full-featured IDE driver to - control up to eight IDE interfaces, each being able to serve a - "master" and a "slave" device, for a total of up to sixteen IDE + control up to ten ATA/IDE interfaces, each being able to serve a + "master" and a "slave" device, for a total of up to twenty ATA/IDE disk/cdrom/tape/floppy drives. People with SCSI-only systems - can say N here. + can say N or M here. Useful information about large (>540 MB) IDE disks, multiple - interfaces, what to do if IDE devices are not automatically - detected, sound card IDE ports, module support, and other topics, is - contained in Documentation/ide.txt. For detailed information about + interfaces, what to do if ATA/IDE devices are not automatically + detected, sound card ATA/IDE ports, module support, and other topics, is + contained in Documentation/ata-ide.txt. For detailed information about hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . - To fine-tune IDE drive/interface parameters for improved + To fine-tune ATA/IDE drive/interface parameters for improved + performance, look for the hdparm package at + ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ . + + To fine-tune ATA/IDE drive/interface parameters for improved performance, look for the hdparm package at ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/ . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt and - Documentation/ide.txt. The module will be called ide.o. Do not - compile this driver as a module if your root file system (the one + Documentation/ide.txt. The module will be called ide-mod.o. Do not + compile this driver as a module if your root filesystem (the one containing the directory /) is located on an IDE device. If you have one or more IDE drives, say Y or M here. If your system @@ -557,13 +561,6 @@ People with SCSI-only systems should say N here. If unsure, say Y. -Cyrix CS5530 MediaGX chipset support -CONFIG_BLK_DEV_CS5530 - Include support for UDMA on the Cyrix MediaGX 5530 chipset. This - will automatically be detected and configured if found. - - It is safe to say Y to this question. - Generic PCI IDE chipset support CONFIG_BLK_DEV_IDEPCI Say Y here for PCI systems which use IDE drive(s). @@ -572,6 +569,15 @@ People with SCSI-only systems should say N here; if unsure say Y. +Support for sharing PCI IDE interrupts +CONFIG_IDEPCI_SHARE_IRQ + Some ATA/IDE chipsets have hardware support which allows for + sharing a single IRQ with other cards. To enable support for + this in the ATA/IDE driver, say Y here. + + It is safe to say Y to this question, in most cases. + If unsure, say N. + Generic PCI bus-master DMA support CONFIG_BLK_DEV_IDEDMA_PCI If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and @@ -584,7 +590,7 @@ the latest version of the hdparm utility from ftp://metalab.unc.edu/pub/Linux/system/hardware/ . - Read the comments at the beginning of drivers/block/idedma.c and the + Read the comments at the beginning of drivers/block/ide-dma.c and the file Documentation/ide.txt for more information. It is safe to say Y to this question. @@ -614,7 +620,7 @@ If you say Y here, and you actually want to reverse the device scan order as explained above, you also need to issue the kernel command - line option "pci=reverse". (Try "man bootparam" or see the + line option "ide=reverse". (Try "man bootparam" or see the documentation of your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time. The lilo procedure is also explained in the SCSI-HOWTO, available from @@ -639,6 +645,23 @@ It is normally safe to answer Y to this question unless your motherboard uses a VIA VP2 chipset, in which case you should say N. +Various ATA, Work(s) In Progress (EXPERIMENTAL) +CONFIG_IDEDMA_PCI_WIP + If you enable this you will be capable of using and testing + highly developmentail projects. + + It is SAFEST to say N to this question. + +3ware Hardware ATA-RAID support (EXPERIMENTAL) +CONFIG_BLK_DEV_3W_XXXX_RAID + 3ware is the only hardware ATA-Raid product in Linux to date. + This card is 2,4, or 8 channel master mode support only. + SCSI support required!!! + + http://www.3ware.com/ + + Please read the comments at the top of drivers/scsi/3w-xxxx.c + AEC6210 chipset support CONFIG_BLK_DEV_AEC6210 This driver adds up to 4 more EIDE devices sharing a single @@ -648,6 +671,12 @@ available". Please read the comments at the top of drivers/block/aec6210.c + If you say Y here, then say Y to "Use DMA by default when available" as well. + +AEC6210 Tuning support (WIP) +CONFIG_AEC6210_TUNING + Please read the comments at the top of drivers/block/aec6210.c + If unsure, say N. ALI M15x3 chipset support CONFIG_BLK_DEV_ALI15X3 @@ -655,9 +684,8 @@ 1535, 1535D onboard chipsets. It also tests for Simplex mode and enables normal dual channel support. - If you say Y here, you also need to say Y to "Use DMA by default - when available", above. Please read the comments at the top of drivers/block/alim15x3.c + If you say Y here, then say Y to "Use DMA by default when available" as well. If unsure, say N. @@ -665,10 +693,14 @@ CONFIG_BLK_DEV_AMD7409 This driver ensures (U)DMA support for AMD756 Viper chipset. - If you say Y here, you also need to say Y to "Use DMA by default - when available", above. Please read the comments at the top of drivers/block/amd7409.c + If you say Y here, then say Y to "Use DMA by default when available" as well. + If unsure, say N. +AMD Viper ATA-66 Override support (WIP) +CONFIG_AMD7409_OVERRIDE + This option auto-forces the ata66 flag. + This effect can be also invoked by calling "idex=ata66" If unsure, say N. CMD64X chipset support @@ -676,8 +708,8 @@ Say Y here if you have an IDE controller which uses any of these chipsets, CMD643, CMD646, or CMD648. -CMD64X chipset RAID support (EXPERIMENTAL) (WIP) -CONFIG_BLK_DEV_CMD64X +CMD64X chipset RAID support (WIP) +CONFIG_CMD64X_RAID Work in progress for hardware raid ata-33/66..........rev 7 minimum. Say N for now. @@ -686,8 +718,14 @@ This driver adds detection and support for the CY82C693 chipset used on Digital's PC-Alpha 164SX boards. - If you say Y here, you need to say Y to "Use DMA by default - when available" as well. + If you say Y here, then say Y to "Use DMA by default when available" as well. + +Cyrix CS5530 MediaGX chipset support +CONFIG_BLK_DEV_CS5530 + Include support for UDMA on the Cyrix MediaGX 5530 chipset. This + will automatically be detected and configured if found. + + It is safe to say Y to this question. HPT34X chipset support CONFIG_BLK_DEV_HPT34X @@ -698,12 +736,13 @@ chipset during the ide-probe at boot time. It is reported to support DVD II drives, by the manufacturer. -HPT34X DMA support (EXPERIMENTAL) -CONFIG_BLK_DEV_HPT34X_DMA - you need to say Y to "Use DMA by default when available" if you say - Y here. - +HPT34X AUTODMA support (WIP) +CONFIG_HPT34X_AUTODMA + This is a dangerous thing to attempt currently! Please read the comments at the top of drivers/block/hpt34x.c + If you say Y here, then say Y to "Use DMA by default when available" as well. + + If unsure, say N. HPT366 chipset support CONFIG_BLK_DEV_HPT366 @@ -716,13 +755,14 @@ manufacturer. Please read the comments at the top of drivers/block/hpt366.c + If you say Y here, then say Y to "Use DMA by default when available" as well. -HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP) -CONFIG_HPT366_FAST_IRQ_PREDICTION +HPT366 Fast Interrupts (WIP) +CONFIG_HPT366_FIP If unsure, say N. -HPT366 mode three unsupported (EXPERIMENTAL) (WIP) +HPT366 mode three unsupported (WIP) CONFIG_HPT366_MODE3 This is an undocumented mode that the HA366 can default to in many cases. If unsure, say N. @@ -748,11 +788,11 @@ Please read the comments at the top of drivers/block/piix.c - Should also include "PIIXn Tuning support" CONFIG_BLK_DEV_PIIX_TUNING + Should also include "PIIXn Tuning support" CONFIG_PIIX_TUNING If unsure, say Y. PIIXn Tuning support -CONFIG_BLK_DEV_PIIX_TUNING +CONFIG_PIIX_TUNING This driver extension adds DMA mode setting and tuning for all PIIX IDE controllers by Intel. Since the BIOS can sometimes improperly set up the device/adapter combination and speed limits, it has @@ -784,15 +824,13 @@ boot-time for max-speed. Note tested limits are UDMA-2. Ultra66 BIOS 1.11 or newer required. - If you say Y here, you need to say Y to "Use DMA by default when - available" as well. - + If you say Y here, then say Y to "Use DMA by default when available" as well. Please read the comments at the top of drivers/block/pdc202xx.c If unsure, say N. Special UDMA Feature -CONFIG_PDC202XX_FORCE_BURST_BIT +CONFIG_PDC202XX_BURST For PDC20246 and PDC20262 Ultra DMA chipsets. Designed originally for PDC20246/Ultra33 that has BIOS setup failures when using 3 or more cards. @@ -801,8 +839,8 @@ If unsure, say N. -Special Mode Feature (EXPERIMENTAL) -CONFIG_PDC202XX_FORCE_MASTER_MODE +Special Mode Feature (WIP) +CONFIG_PDC202XX_MASTER For PDC20246 and PDC20262 Ultra DMA chipsets. This is reserved for possible Hardware RAID 0,1 for the FastTrak Series. @@ -832,8 +870,7 @@ (while running a "cat") provided you enabled "proc" support. Please read the comments at the top of drivers/block/via82cxxx.c - If you say Y here, you also need to say Y to "Use DMA by default - when available", above. + If you say Y here, then say Y to "Use DMA by default when available" as well. If unsure, say N. @@ -908,16 +945,6 @@ See the files Documentation/ide.txt and drivers/block/umc8672.c for more info. -PS/2 ESDI hard disk support -CONFIG_BLK_DEV_PS2 - Say Y here if you have a PS/2 machine with a MCA bus and an ESDI - hard disk. - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be - called ps2esdi.o. - Amiga builtin Gayle IDE interface support CONFIG_BLK_DEV_GAYLE This is the IDE driver for the builtin IDE interface on some Amiga @@ -968,7 +995,14 @@ Use DMA by default CONFIG_IDEDMA_PMAC_AUTO - No help for CONFIG_IDEDMA_PMAC_AUTO + Prior to kernel version 2.1.112, Linux used to automatically use + DMA for IDE drives and chipsets which support it. Due to concerns + about a couple of cases where buggy hardware may have caused damage, + the default is now to NOT use DMA automatically. To revert to the + previous behaviour, say Y to this question. + + If you suspect your hardware is at all flakey, say N here. + Do NOT email the IDE kernel people regarding this issue! Macintosh Quadra/Powerbook IDE interface support CONFIG_BLK_DEV_MAC_IDE @@ -981,9 +1015,16 @@ devices (hard disks, CD-ROM drives, etc.) that are connected to the builtin IDE interface. +IDE card support +CONFIG_BLK_DEV_IDE_CARDS + On Acorn systems, say Y here if you wish to use an IDE interface + expansion card. If you do not or are unsure, say N to this. + ICS IDE interface support CONFIG_BLK_DEV_IDE_ICSIDE - No help for CONFIG_BLK_DEV_IDE_ICSIDE + On Acorn systems, say Y here if you wish to use the ICS IDE + interface card. This is not required for ICS partition support. + If you are unsure, say N to this. ICS DMA support CONFIG_BLK_DEV_IDEDMA_ICS @@ -991,7 +1032,14 @@ Use ICS DMA by default CONFIG_IDEDMA_ICS_AUTO - No help for CONFIG_IDEDMA_ICS_AUTO + Prior to kernel version 2.1.112, Linux used to automatically use + DMA for IDE drives and chipsets which support it. Due to concerns + about a couple of cases where buggy hardware may have caused damage, + the default is now to NOT use DMA automatically. To revert to the + previous behaviour, say Y to this question. + + If you suspect your hardware is at all flakey, say N here. + Do NOT email the IDE kernel people regarding this issue! RapIDE interface support CONFIG_BLK_DEV_IDE_RAPIDE @@ -1009,6 +1057,16 @@ It's pretty unlikely that you have one of these: say N. +PS/2 ESDI hard disk support +CONFIG_BLK_DEV_PS2 + Say Y here if you have a PS/2 machine with a MCA bus and an ESDI + hard disk. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be + called ps2esdi.o. + Mylex DAC960/DAC1100 PCI RAID Controller support CONFIG_BLK_DEV_DAC960 This driver adds support for the Mylex DAC960, AcceleRAID, and @@ -1392,20 +1450,47 @@ This is a machine with a R4400 100 MHz CPU. To compile a Linux kernel that runs on these, say Y here. For details about Linux on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at - http://lena.fnet.fr/ . + http://oss.sgi.com/mips. Support for Acer PICA 1 chipset CONFIG_ACER_PICA_61 This is a machine with a R4400 133/150 MHz CPU. To compile a Linux kernel that runs on these, say Y here. For details about Linux on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at - http://lena.fnet.fr/ . + http://oss.sgi.com/mips. Support for Algorithmics P4032 (EXPERIMENTAL) CONFIG_ALGOR_P4032 This is an evaluation board of the British company Algorithmics. The board uses the R4300 and a R5230 CPUs. For more information about - this board see http://www.algor.co.uk . + this board see http://www.algor.co.uk. + +Support for BAGET MIPS series +CONFIG_BAGET_MIPS + This enables support for the Baget, a Russian embedded system. For + more details about the Baget see the Linux/MIPS FAQ on + http://oss.sgi.com/mips. + +Support for DECstations +CONFIG_DECSTATION + This enables support for DEC's MIPS based workstations. For details + see the Linux/MIPS FAQ on http://oss.sgi.com/mips. the + DECstation porting pages on http://decstation.unix-ag.org. + + If you have one of the following DECstation Models you definitely + want to choose R4xx0 for the CPU Type: + + DECstation 5000/50 + DECstation 5000/150 + DECstation 5000/260 + DECsystem 5900/260 + + otherwise choose R3000. + +Support for NEC DDB Vrc-5074 +CONFIG_DDB5074 + This enables support for the VR5000-based NEC DDB Vrc-5074 evaluation + board. IDE card support CONFIG_BLK_DEV_IDE_CARDS @@ -1423,34 +1508,67 @@ This allows Linux on Acorn systems to determine its partitions in the 'non-ADFS' partition area of the hard disk - usually located after the ADFS partition. You are probably using this system, so - you should say Y here. + you should say Y it. Support for Mips Magnum 4000 CONFIG_MIPS_MAGNUM_4000 This is a machine with a R4000 100 MHz CPU. To compile a Linux kernel that runs on these, say Y here. For details about Linux on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at - http://lena.fnet.fr/ . + http://oss.sgi.com/mips. Support for Olivetti M700 CONFIG_OLIVETTI_M700 This is a machine with a R4000 100 MHz CPU. To compile a Linux kernel that runs on these, say Y here. For details about Linux on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at - http://lena.fnet.fr/ . + http://oss.sgi.com/mips. + +Support for SGI IP22 +CONFIG_SGI_IP22 + This are the SGI Indy, Challenge S and Indigo2, as well as certain OEM + variants like the Tandem CMN B006S. To compile a Linux kernel that + runs on these, say Y here. + +Support for SGI IP27 + This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics + workstations. To compile a Linux kernel that runs on these, say Y + here. + +IP27 N-Mode +CONFIG_SGI_SN0_N_MODE + The nodes of Origin 200, Origin 2000 and Onyx 2 systems can be + configured in either N-Modes which allows for more nodes or M-Mode + which allows for more more memory. Your system is most probly + running in M-Mode, so you should say N here. + +MIPS JAZZ onboard SONIC Ethernet support +CONFIG_MIPS_JAZZ_SONIC + This is the driver for the onboard card of of MIPS Magnum 4000, + Acer PICA, Olivetti M700-10 and a few other identical OEM systems. + +MIPS JAZZ FAS216 SCSI support +CONFIG_JAZZ_ESP + This is the driver for the onboard SCSI hostadapter of MIPS Magnum 4000, + Acer PICA, Olivetti M700-10 and a few other identical OEM systems. CPU type CONFIG_CPU_R3000 - Give the type of your machine's MIPS CPU. For this question, it - suffices to give a unique prefix of the option you want to choose. - In case of doubt select the R3000 CPU. The kernel will then run on - other MIPS machines but with slightly reduced performance. - -Compile the kernel into the ECOFF object format -CONFIG_ECOFF_KERNEL - Some machines require a kernel in the ECOFF format. You will have to - say Y here for example if you want to use a Mips Magnum 3000 or a - DECstation. + Please make shure to pick the right CPU type. Linux/MIPS is not + designed to be generic, i.e. Kernels compiled for R3000 CPUs will + *not* work on R4000 Machines and vice versa. + However, since most the supported Machines have an R4000 (or similar) + CPU R4xx0 might be a safe bet. + If the resulting Kernel does not work try to recompile with R3000. + +Support for large 64-bit configurations +CONFIG_MIPS_INSANE_LARGE + MIPS R10000 does support a 44 bit / 16TB address space as opposed to + previous 64-bit processors which only did only support 40 bit / 1TB. If + you need processes of more than 1TB virtual address space activate this. + Activating CONFIG_MIPS_INSANE_LARGE results in additional memory usage, + so only activate this if you really need. Very few people will need + this. Generate little endian code CONFIG_CPU_LITTLE_ENDIAN @@ -1539,7 +1657,7 @@ Chances are that you should say Y here if you compile a kernel which will run as a router and N for regular hosts. If unsure, say N. -SIN flood protection +SYN flood protection CONFIG_SYN_COOKIES Normal TCP/IP networking is open to an attack known as "SYN flooding". This denial-of-service attack prevents legitimate remote @@ -1712,6 +1830,10 @@ servicing. Say Y here to enable the serial driver to take advantage of those special I/O ports. +SGI PROM Console Support +CONFIG_SGI_PROM_CONSOLE + Enable this if you want to use the PROMs for console I/O. + SGI Zilog85C30 serial support CONFIG_SGI_SERIAL If you want to use your SGI's built-in serial ports under Linux, @@ -1724,6 +1846,25 @@ /dev/graphics and /dev/gfx drivers into the kernel for supporting virtualized access to your graphics hardware. +SGI Newport Console support +CONFIG_SGI_NEWPORT_CONSOLE + Enable this if you want the console on the Newport aka XL graphics + card of your Indy. Most people say Y here. + +SGI DS1286 RTC support +CONFIG_SGI_DS1286 + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the real time clock built into your computer. + Every SGI has such a clock built in. It reports status information + via the file /proc/rtc and its behaviour is set by various ioctls on + /dev/rtc. + +SGI Vino Video For Linux (EXPERIMENTAL) +CONFIG_SGI_VIDEO_VINO + Support for the SGI Vino Video hardware which is part of the Newport + aka XL graphics card. Most people will say N here. + Support the Bell Technologies HUB6 card CONFIG_HUB6 Say Y here to enable support in the dumb serial driver to support @@ -1899,7 +2040,7 @@ Say Y here if you would like Linux to configure your Plug and Play devices. You should then also say Y to "ISA Plug and Play support", below. Alternatively, you can configure your PnP devices using the - user space utilities contained in the ISAPNP tools package. + user space utilities contained in the isapnptools package. This support is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -2457,6 +2598,52 @@ you select "Advanced lowlevel driver options", you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can also use font widths different from 8. + + If you need support for G400 secondary head, you must first enable + I2C support and I2C bit-banging support in character devices section, + and then Matrox I2C support and G400 secondary head support here + in framebuffer section. + +Matrox I2C support +CONFIG_FB_MATROX_I2C + This drivers creates I2C buses which are needed for accessing + DDC (I2C) bus present on all Matroxes, I2C bus which interconnects + Matrox optional devices, like MGA-TVO on G200 and G400, and + secondary head DDC bus, present on G400 only. + + You can say Y or M here if you want to experiment with monitor + detection code. You must say Y or M here if you want to use either + second head of G400 or MGA-TVO on G200 or G400. + + If you compile it as module, it will create module named i2c-matroxfb.o. + +Matrox G400 second head support +CONFIG_FB_MATROX_MAVEN + Say Y or M here if you want to use secondary head on G400 or MGA-TVO + add-on on G200. Secondary head is not compatible with accelerated + XFree 3.3.x SVGA servers - secondary head output is blanked while you + are in X. With XFree 3.9.17 preview you can use both heads if you use + SVGA over fbdev or fbdev driver on first head and fbdev driver on + second head. + + If you compile it as module, two modules are created, matroxfb_crtc2.o + and matroxfb_maven.o. Matroxfb_maven is needed for both G200 and G400, + matroxfb_crtc2 is needed only by G400. You must also load i2c-matroxfb + to get it to run. + + Driver starts in monitor mode and you must use matroxset tool (available + at ftp://platan.vc.cvut.cz/pub/linux/matrox-latest) to switch it to PAL + or NTSC or to swap primary and secondary head outputs. Secondary head + driver also always start in 640x480 resolution, you must use fbset to + change it. + + Also do not forget that second head supports only 16 and 32 bpp packed + pixels, so it is good idea to compile them into kernel too. You can + use only some font widths, as driver uses generic painting procedures + (secondary head does not use acceleration engine). + + There is no need for enabling 'Matrox multihead support' if you have + only one Matrox card in the box. Matrox unified driver multihead support CONFIG_FB_MATROX_MULTIHEAD @@ -4143,6 +4330,82 @@ speed of the driver, and the size of your syslog files! When inactive, they will have only a modest impact on performance. +FORE Systems 200E-series +CONFIG_ATM_FORE200E + This is a driver for the FORE Systems 200E-series ATM adapter + cards. It simultaneously supports PCA-200E and SBA-200E models + on PCI and SBUS hosts. Say Y (or M to compile as a module + named fore_200e.o) here if you have one of these ATM adapters. + + See the file Documentation/networking/fore200e.txt for further + details. + +Enable PCA-200E card support on PCI-based hosts +CONFIG_ATM_FORE200E_PCA + Enable this if you want your PCA-200E cards to be probed. + +Use default PCA-200E firmware +CONFIG_ATM_FORE200E_PCA_DEFAULT_FW + Use the default PCA-200E firmware data shipped with the driver. + + Normal users do not have to deal with the firmware stuff, so + this feature is normally enabled. + +Pathname of user-supplied binary firmware +CONFIG_ATM_FORE200E_PCA_FW + This defines the pathname of an alternative PCA-200E binary + firmware image supplied by the user. This pathname may be + absolute or relative to the drivers/atm directory. + + The driver comes with an adequate firmware image, so normal users + do not have to supply an alternative one. They just enable the use + of the default firmware instead. + +Enable SBA-200E card support on SBUS-based hosts +CONFIG_ATM_FORE200E_SBA + Enable this if you want your SBA-200E cards to be probed. + +Use default SBA-200E firmware +CONFIG_ATM_FORE200E_SBA_DEFAULT_FW + Use the default SBA-200E firmware data shipped with the driver. + + Normal users do not have to deal with the firmware stuff, so + this feature is normally enabled. + +Pathname of user-supplied binary firmware +CONFIG_ATM_FORE200E_SBA_FW + This defines the pathname of an alternative SBA-200E binary + firmware image supplied by the user. This pathname may be + absolute or relative to the drivers/atm directory. + + The driver comes with an adequate firmware image, so normal users + do not have to supply an alternative one. They just enable the use + of the default firmware instead. + +Maximum number of tx retries +CONFIG_ATM_FORE200E_TX_RETRY + Specifies the number of times the driver attempts to transmit + a message before giving up, if the transmit queue of the ATM card + is transiently saturated. + + Saturation of the transmit queue may occur only under extreme + conditions, e.g. when a fast host continuously submits very small + frames (<64 bytes) or raw AAL0 cells (48 bytes) to the ATM adapter. + + Note that under common conditions, it is unlikely that you encounter + a saturation of the transmit queue, so the retry mechanism never + comes into play. + +Debugging level (0-3) +CONFIG_ATM_FORE200E_DEBUG + Specifies the level of debugging messages issued by the driver. + The verbosity of the driver increases with the value of this + parameter. + + When active, these messages can have a significant impact on + the performances of the driver, and the size of your syslog files! + Keep the debugging level to 0 during normal operations. + SCSI support? CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or @@ -7475,6 +7738,11 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +EtherExpress PRO/100 support +CONFIG_EEPRO100_PM (EXPERIMENTAL) + If you want to play around with power management code + that has reported to lock up some machines, say Y here. + ICL EtherTeam 16i/32 support (EXPERIMENTAL) CONFIG_ETH16I If you have a network (Ethernet) card of this type, say Y and read @@ -11679,6 +11947,12 @@ Say Y here if you are compiling the kernel on a different architecture than the one it is intended to run on. +Kernel support for Linux/MIPS 32-bit binary compatibility +CONFIG_MIPS32_COMPAT + Select this option this option if you want Linux/MIPS 32-bit binary + compatibility. Since all software available available for Linux/MIPS + is currently 32-bit you should say Y here. + Build fp exception handler module CONFIG_MIPS_FPE_MODULE Build the floating point exception handler module. This option is @@ -13938,7 +14212,7 @@ # LocalWords: PMAX MILO Alphas Multia Tseng linuxelf endian mipsel mips drv HT # LocalWords: kerneld callouts AdvanSys advansys Admin WDT DataStor EP verden # LocalWords: wdt hdb hdc bugfix SiS vlb Acculogic CSA DTC dtc Holtek ht QDI -# LocalWords: QD qd UMC umc ALI ali lena fnet fr azstarnet cdr fb MDA ps esdi +# LocalWords: QD qd UMC umc ALI ali oss sgi com azstarnet cdr fb MDA ps esdi # LocalWords: Avanti XL AlphaStations Jensen DECpc AXPpci UDB Cabriolet MCA RC # LocalWords: AlphaPC mca AOUT OUTput PPro sipx gwdg lo nwe FourPort Boca unm # LocalWords: Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT diff -u --recursive --new-file v2.3.47/linux/Documentation/IRQ-affinity.txt linux/Documentation/IRQ-affinity.txt --- v2.3.47/linux/Documentation/IRQ-affinity.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/IRQ-affinity.txt Thu Feb 24 22:41:16 2000 @@ -0,0 +1,37 @@ + +SMP IRQ affinity, started by Ingo Molnar + + +/proc/irq/IRQ#/smp_affinity specifies which target CPUs are permitted +for a given IRQ source. It's a bitmask of allowed CPUs. It's not allowed +to turn off all CPUs, and if an IRQ controller does not support IRQ +affinity then the value will not change from the default 0xffffffff. + +Here is an example of restricting IRQ44 (eth1) to CPU0-3 then restricting +the IRQ to CPU4-8 (this is an 8-CPU SMP box): + +[root@moon 44]# cat smp_affinity +ffffffff +[root@moon 44]# echo 0f > smp_affinity +[root@moon 44]# cat smp_affinity +0000000f +[root@moon 44]# ping -f h +PING hell (195.4.7.3): 56 data bytes +... +--- hell ping statistics --- +6029 packets transmitted, 6027 packets received, 0% packet loss +round-trip min/avg/max = 0.1/0.1/0.4 ms +[root@moon 44]# cat /proc/interrupts | grep 44: + 44: 0 1785 1785 1783 1783 1 +1 0 IO-APIC-level eth1 +[root@moon 44]# echo f0 > smp_affinity +[root@moon 44]# ping -f h +PING hell (195.4.7.3): 56 data bytes +.. +--- hell ping statistics --- +2779 packets transmitted, 2777 packets received, 0% packet loss +round-trip min/avg/max = 0.1/0.5/585.4 ms +[root@moon 44]# cat /proc/interrupts | grep 44: + 44: 1068 1785 1785 1784 1784 1069 1070 1069 IO-APIC-level eth1 +[root@moon 44]# + diff -u --recursive --new-file v2.3.47/linux/Documentation/fb/matroxfb.txt linux/Documentation/fb/matroxfb.txt --- v2.3.47/linux/Documentation/fb/matroxfb.txt Thu Apr 29 11:53:41 1999 +++ linux/Documentation/fb/matroxfb.txt Mon Feb 21 11:08:22 2000 @@ -105,7 +105,7 @@ Configuration ============= -You can pass kernel command line options to vesafb with +You can pass kernel command line options to matroxfb with `video=matrox:option1,option2:value2,option3' (multiple options should be separated by comma, values are separated from options by `:'). Accepted options: @@ -276,16 +276,16 @@ + color keying is not supported + feature connector of Mystique and Gx00 is set to VGA mode (it is disabled by BIOS) - + DCC (monitor detection) protocol is not implemented + + DDC (monitor detection) is supported through dualhead driver + some check for input values are not so strict how it should be (you can specify vslen=4000 and so on). + maybe more... And following features: + 4bpp is available only on Millennium I and Millennium II. It is hardware limitation. - + current fbset is not able to set 15bpp videomode: you must specify - depth==16 and green.length==5. fbset does not allow you to set - green.length. + + selection between 1:5:5:5 and 5:6:5 16bpp videomode is done by -rgba + option of fbset: "fbset -depth 16 -rgba 5,5,5" selects 1:5:5:5, anything + else selects 5:6:5 mode. + text mode uses 6 bit VGA palette instead of 8 bit (one of 262144 colors instead of one of 16M colors). It is due to hardware limitation of Millennium I/II and SVGALib compatibility. @@ -329,6 +329,27 @@ 8x16 Millennium I G200 TEXT 3.29 1.50 + + +Dualhead G400 +============= +Driver supports dualhead G400 with some limitations: + + secondary head shares videomemory with primary head. It is not problem + if you have 32MB of videoram, but if you have only 16MB, you may have + to think twice before choosing videomode (for example twice 1880x1440x32bpp + is not possible). + + due to hardware limitation, secondary head can use only 16 and 32bpp + videomodes. + + secondary head is not accelerated. There were bad problems with accelerated + XFree when secondary head used to use acceleration. + + secondary head always powerups in 640x480@60-32 videomode. You have to use + fbset to change this mode. + + secondary head always powerups in monitor mode. You have to use matroxset + to change it to TV mode. Also, you must select at least 525 lines for + NTSC output and 625 lines for PAL output. + + kernel is not fully multihead ready. So some things are impossible to do. + + if you compiled it as module, you must insert i2c-matroxfb, matroxfb_maven + and matroxfb_crtc2 into kernel. * Yes, it is slower than Millennium I. diff -u --recursive --new-file v2.3.47/linux/Documentation/floppy.txt linux/Documentation/floppy.txt --- v2.3.47/linux/Documentation/floppy.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/floppy.txt Mon Feb 21 11:04:30 2000 @@ -0,0 +1,222 @@ +This file describes the floppy driver. + +FAQ list: +========= + + A FAQ list may be found in the fdutils package (see below), and also +at http://fdutils.linux.lu/FAQ.html + + +LILO configuration options (Thinkpad users, read this) +====================================================== + + The floppy driver is configured using the 'floppy=' option in +lilo. This option can be typed at the boot prompt, or entered in the +lilo configuration file. + Example: If your kernel is called linux-2.2.13, type the following line +at the lilo boot prompt (if you have a thinkpad): + linux-2.2.13 floppy=thinkpad +You may also enter the following line in /etc/lilo.conf, in the description +of linux-2.2.13: + append = "floppy=thinkpad" + + Several floppy related options may be given, example: + linux-2.2.13 floppy=daring floppy=two_fdc + append = "floppy=daring floppy=two_fdc" + + If you give options both in the lilo config file and on the boot +prompt, the option strings of both places are concatenated, the boot +prompt options coming last. That's why there are also options to +restore the default behavior. + + If you use the floppy driver as a module, use the following syntax: + insmod floppy + +Example: + insmod floppy daring two_fdc + + Some versions of insmod are buggy in one way or another. If you have +any problems (options not being passed correctly, segfaults during +insmod), first check whether there is a more recent version. + + The floppy related options include: + + floppy=asus_pci + Sets the bit mask to allow only units 0 and 1. (default) + + floppy=daring + Tells the floppy driver that you have a well behaved floppy controller. + This allows more efficient and smoother operation, but may fail on + certain controllers. This may speed up certain operations. + + floppy=0,daring + Tells the floppy driver that your floppy controller should be used + with caution. + + floppy=one_fdc + Tells the floppy driver that you have only one floppy controller. + (default) + + floppy=two_fdc + floppy=
,two_fdc + Tells the floppy driver that you have two floppy controllers. + The second floppy controller is assumed to be at
. + This option is not needed if the second controller is at address + 0x370, and if you use the 'cmos' option. + + floppy=thinkpad + Tells the floppy driver that you have a Thinkpad. Thinkpads use an + inverted convention for the disk change line. + + floppy=0,thinkpad + Tells the floppy driver that you don't have a Thinkpad. + + floppy=omnibook + floppy=nodma + Tells the floppy driver not to use Dma for data transfers. + This is needed on HP Omnibooks, which don't have a workable + DMA channel for the floppy driver. This option is also useful + if you frequently get "Unable to allocate DMA memory" messages. + Indeed, dma memory needs to be continuous in physical memory, + and is thus harder to find, whereas non-dma buffers may be + allocated in virtual memory. However, I advise against this if + you have an FDC without a FIFO (8272A or 82072). 82072A and + later are OK. You also need at least a 486 to use nodma. + If you use nodma mode, I suggest you also set the FIFO + threshold to 10 or lower, in order to limit the number of data + transfer interrupts. + + If you have a FIFO-able FDC, the floppy driver automatically + falls back on non DMA mode if no DMA-able memory can be found. + If you want to avoid this, explicitely ask for 'yesdma'. + + floppy=yesdma + Tells the floppy driver that a workable DMA channel is available. + (default) + + floppy=nofifo + Disables the FIFO entirely. This is needed if you get "Bus + master arbitration error" messages from your Ethernet card (or + from other devices) while accessing the floppy. + + floppy=fifo + Enables the FIFO. (default) + + floppy=,fifo_depth + Sets the FIFO threshold. This is mostly relevant in DMA + mode. If this is higher, the floppy driver tolerates more + interrupt latency, but it triggers more interrupts (i.e. it + imposes more load on the rest of the system). If this is + lower, the interrupt latency should be lower too (faster + processor). The benefit of a lower threshold is less + interrupts. + To tune the fifo threshold, switch on over/underrun messages + using 'floppycontrol --messages'. Then access a floppy + disk. If you get a huge amount of "Over/Underrun - retrying" + messages, then the fifo threshold is too low. Try with a + higher value, until you only get an occasional Over/Underrun. + It is a good idea to compile the floppy driver as a module + when doing this tuning. Indeed, it allows to try different + fifo values without rebooting the machine for each test. Note + that you need to do 'floppycontrol --messages' every time you + re-insert the module. + Usually, tuning the fifo threshold should not be needed, as + the default (0xa) is reasonable. + + floppy=,,cmos + Sets the CMOS type of to . This is mandatory if + you have more than two floppy drives (only two can be + described in the physical CMOS), or if your BIOS uses + non-standard CMOS types. The CMOS types are: + 0 - Use the value of the physical CMOS + 1 - 5 1/4 DD + 2 - 5 1/4 HD + 3 - 3 1/2 DD + 4 - 3 1/2 HD + 5 - 3 1/2 ED + 6 - 3 1/2 ED + 16 - unknown or not installed + (Note: there are two valid types for ED drives. This is because 5 was + initially chosen to represent floppy *tapes*, and 6 for ED drives. + AMI ignored this, and used 5 for ED drives. That's why the floppy + driver handles both.) + + floppy=unexpected_interrupts + Print a warning message when an unexpected interrupt is received. + (default) + + floppy=no_unexpected_interrupts + floppy=L40SX + Don't print a message when an unexpected interrupt is received. This + is needed on IBM L40SX laptops in certain video modes. (There seems + to be an interaction between video and floppy. The unexpected + interrupts affect only performance, and can be safely ignored.) + + floppy=broken_dcl + Don't use the disk change line, but assume that the disk was + changed whenever the device node is reopened. Needed on some + boxes where the disk change line is broken or unsupported. + This should be regarded as a stopgap measure, indeed it makes + floppy operation less efficient due to unneeded cache + flushings, and slightly more unreliable. Please verify your + cable, connection and jumper settings if you have any DCL + problems. However, some older drives, and also some laptops + are known not to have a DCL. + + floppy=debug + Print debugging messages. + + floppy=messages + Print informational messages for some operations (disk change + notifications, warnings about over and underruns, and about + autodetection). + + floppy=silent_dcl_clear + Uses a less noisy way to clear the disk change line (which + doesn't involve seeks). Implied by 'daring' option. + + floppy=,irq + Sets the floppy IRQ to instead of 6. + + floppy=,dma + Sets the floppy DMA channel to instead of 2. + + floppy=slow + Use PS/2 stepping rate: + " PS/2 floppies have much slower step rates than regular floppies. + It's been recommended that take about 1/4 of the default speed + in some more extreme cases." + + + +Supporting utilities and additional documentation: +================================================== + + Additional parameters of the floppy driver can be configured at +runtime. Utilities which do this can be found in the fdutils package. +This package also contains a new version of mtools which allows to +access high capacity disks (up to 1992K on a high density 3 1/2 disk!). +It also contains additional documentation about the floppy driver. + +The latest version can be found at fdutils homepage: + http://fdutils.linux.lu + +The fdutils-5.3 release can be found at: + http://fdutils.linux.lu/fdutils-5.3.src.tar.gz + http://www.tux.org/pub/knaff/fdutils/fdutils-5.3.src.tar.gz + ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-5.3.src.tar.gz + ftp://metalab.unc.edu/pub/Linux/utils/disk-management/fdutils-5.3.src.tar.gz + +Reporting problems about the floppy driver +========================================== + + If you have a question or a bug report about the floppy driver, mail +me at Alain.Knaff@poboxes.com . If you post to Usenet, preferably use +comp.os.linux.hardware. As the volume in these groups is rather high, +be sure to include the word "floppy" (or "FLOPPY") in the subject +line. If the reported problem happens when mounting floppy disks, be +sure to mention also the type of the filesystem in the subject line. + + Be sure to read the FAQ before mailing/posting any bug reports! + + Alain diff -u --recursive --new-file v2.3.47/linux/Documentation/ide.txt linux/Documentation/ide.txt --- v2.3.47/linux/Documentation/ide.txt Fri Jan 21 18:19:15 2000 +++ linux/Documentation/ide.txt Sat Feb 26 20:32:12 2000 @@ -38,7 +38,7 @@ - interface PIO timing & prefetch parameter support - experimental support for UMC 8672 interfaces - support for secondary interface on the FGI/Holtek HT-6560B VLB i/f - - use kernel command line option: ide0=ht6560 + - use kernel command line option: ide0=ht6560b - experimental support for various IDE chipsets - use appropriate kernel command line option from list below - support for drives with a stuck WRERR_STAT bit diff -u --recursive --new-file v2.3.47/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.3.47/linux/Documentation/ioctl-number.txt Tue Nov 23 22:42:20 1999 +++ linux/Documentation/ioctl-number.txt Mon Feb 21 11:08:22 2000 @@ -128,7 +128,8 @@ 'm' all linux/soundcard.h conflict! 'm' all linux/synclink.h conflict! 'm' 00-1F net/irda/irmod.h conflict! -'n' all linux/ncp_fs.h +'n' 00-7F linux/ncp_fs.h +'n' E0-FF video/matrox.h matroxfb 'p' 00-3F linux/mc146818rtc.h 'p' 40-7F linux/nvram.h 'p' 80-9F user-space parport diff -u --recursive --new-file v2.3.47/linux/Documentation/m68k/README.buddha linux/Documentation/m68k/README.buddha --- v2.3.47/linux/Documentation/m68k/README.buddha Wed Dec 31 16:00:00 1969 +++ linux/Documentation/m68k/README.buddha Mon Feb 21 11:04:30 2000 @@ -0,0 +1,210 @@ + +The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by +Geert Uytterhoeven based on the following specifications: + +------------------------------------------------------------------------ + +Register map of the Buddha IDE controller and the +Buddha-part of the Catweasel Zorro-II version + +The Autoconfiguration has been implemented just as Commodore +described in their manuals, no tricks have been used (for +example leaving some address lines out of the equations...). +If you want to configure the board yourself (for example let +a Linux kernel configure the card), look at the Commodore +Docs. Reading the nibbles should give this information: + +Vendor number: 4626 ($1212) +product number: 0 (42 for Catweasel Z-II) +Serial number: 0 +Rom-vector: $1000 + +The card should be a Z-II board, size 64K, not for freemem +list, Rom-Vektor is valid, no second Autoconfig-board on the +same card, no space preferrence, supports "Shutup_forever". + +Setting the base address should be done in two steps, just +as the Amiga Kickstart does: The lower nibble of the 8-Bit +address is written to $4a, then the whole Byte is written to +$48, while it doesn't matter how often you're writing to $4a +as long as $48 is not touched. After $48 has been written, +the whole card disappears from $e8 and is mapped to the new +addrress just written. Make shure $4a is written befor $48, +otherwise your chance is only 1:16 to find the board :-). + +The local memory-map is even active when mapped to $e8: + +$0-$7e Autokonfig-space, see Z-II docs. + +$80-$7fd reserved + +$7fe Speed-select Register: Read & Write + (description see further down) + +$800-$8ff IDE-Select 0 (Port 0, Register set 0) + +$900-$9ff IDE-Select 1 (Port 0, Register set 1) + +$a00-$aff IDE-Select 2 (Port 1, Register set 0) + +$b00-$bff IDE-Select 3 (Port 1, Register set 1) + +$c00-$cff IDE-Select 4 (Port 2, Register set 0, + Catweasel only!) + +$d00-$dff IDE-Select 5 (Port 3, Register set 1, + Catweasel only!) + +$e00-$eff local expansion port, on Catweasel Z-II the + Catweasel registers are also mapped here. + Never touch, use multidisk.device! + +$f00 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 0. + +$f01-$f3f mirror of $f00 + +$f40 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 1. + +$f41-$f7f mirror of $f40 + +$f80 read only, Byte-access: Bit 7 shows the + level of the IRQ-line of IDE port 2. + (Catweasel only!) + +$f81-$fbf mirror of $f80 + +$fc0 write-only: Writing any value to this + register enables IRQs to be passed from the + IDE ports to the Zorro bus. This mechanism + has been implemented to be compatible with + harddisks that are either defective or have + a buggy firmware and pull the IRQ line up + while starting up. If interrupts would + always be passed to the bus, the computer + might not start up. Once enabled, this flag + can not be disabled again. The level of the + flag can not be determined by software + (what for? Write to me if it's necessary!). + +$fc1-$fff mirror of $fc0 + +$1000-$ffff Buddha-Rom with offset $1000 in the rom + chip. The addresses $0 to $fff of the rom + chip cannot be read. Rom is Byte-wide and + mapped to even addresses. + +The IDE ports issue an INT2. You can read the level of the +IRQ-lines of the IDE-ports by reading from the three (two +for Buddha-only) registers $f00, $f40 and $f80. This way +more than one I/O request can be handled and you can easily +determine what driver has to serve the INT2. Buddha and +Catweasel expansion boards can issue an INT6. A seperate +memory map is available for the I/O module and the sysop's +I/O module. + +The IDE ports are fed by the address lines A2 to A4, just as +the Amiga 1200 and Amiga 4000 IDE ports are. This way +existing drivers can be easily ported to Buddha. A move.l +polls two words out of the same address of IDE port since +every word is mirrored once. movem is not possible, but +it's not necessary either, because you can only speedup +68000 systems with this technique. A 68020 system with +fastmem is faster with move.l. + +If you're using the mirrored registers of the IDE-ports with +A6=1, the Buddha doesn't care about the speed that you have +selected in the speed register (see further down). With +A6=1 (for example $840 for port 0, register set 0), a 780ns +access is being made. These registers should be used for a +command access to the harddisk/CD-Rom, since command +accesses are Byte-wide and have to be made slower according +to the ATA-X3T9 manual. + +Now for the speed-register: The register is byte-wide, and +only the upper three bits are used (Bits 7 to 5). Bit 4 +must always be set to 1 to be compatible with later Buddha +versions (if I'll ever update this one). I presume that +I'll never use the lower four bits, but they have to be set +to 1 by definition. + The values in this table have to be shifted 5 bits to the +left and or'd with $1f (this sets the lower 5 bits). + +All the timings have in common: Select and IOR/IOW rise at +the same time. IOR and IOW have a propagation delay of +about 30ns to the clocks on the Zorro bus, that's why the +values are no multiple of 71. One clock-cycle is 71ns long +(exactly 70,5 at 14,18 Mhz on PAL systems). + +value 0 (Default after reset) + +497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles) +(same timing as the Amiga 1200 does on it's IDE port without +accelerator card) + +value 1 + +639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles) + +value 2 + +781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles) + +value 3 + +355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) + +value 4 + +355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles) + +value 5 + +355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles) + +value 6 + +1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles) + +value 7 + +355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) + +When accessing IDE registers with A6=1 (for example $84x), +the timing will always be mode 0 8-bit compatible, no matter +what you have selected in the speed register: + +781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive. + +All the timings with a very short select-signal (the 355ns +fast accesses) depend on the accelerator card used in the +system: Sometimes two more clock cycles are inserted by the +bus interface, making the whole access 497ns long. This +doesn't affect the reliability of the controller nor the +performance of the card, since this doesn't happen very +often. + +All the timings are calculated and only confirmed by +measurements that allowed me to count the clock cycles. If +the system is clocked by an oscillator other than 28,37516 +Mhz (for example the NTSC-frequency 28,63636 Mhz), each +clock cycle is shortened to a bit less than 70ns (not worth +mentioning). You could think of a small performance boost +by overclocking the system, but you would either need a +multisync monitor, or a graphics card, and your internal +diskdrive would go crazy, that's why you shouldn't tune your +Amiga this way. + +Giving you the possibility to write software that is +compatible with both the Buddha and the Catweasel Z-II, The +Buddha acts just like a Catweasel Z-II with no device +connected to the third IDE-port. The IRQ-register $f80 +always shows a "no IRQ here" on the Buddha, and accesses to +the third IDE port are going into data's Nirwana on the +Buddha. + + Jens Schönfeld february 19th, 1997 + updated may 27th, 1997 + eMail: sysop@nostlgic.tng.oche.de + diff -u --recursive --new-file v2.3.47/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt --- v2.3.47/linux/Documentation/networking/8139too.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/8139too.txt Thu Feb 24 10:11:24 2000 @@ -0,0 +1,194 @@ + + "8139too" Fast Ethernet driver for Linux + Improved support for RTL-8139 Fast Ethernet adapters + + Copyright 2000 Jeff Garzik + + + Architectures supported (all PCI platforms): + x86, Alpha AXP, PowerPC, Sparc64 + + + + +Disclaimer +---------- + +THIS DRIVER IS A DEVELOPMENT RELEASE FOR A DEVELOPMENT KERNEL. DO NOT +USE IN A PRODUCTION ENVIRONMENT. + +DO NOT CONTACT DONALD BECKER FOR SUPPORT OF THIS DRIVER, his driver is +completely different and maintained independently of the 8139too code base. + + + +Requirements +------------ +Kernel 2.3.41 or later. +A Fast Ethernet adapter containing an RTL8139-based chip. + + + +Introduction +------------ + +The "8139too" Fast Ethernet driver for Linux 2.4.0 is a substantial +modification of the experimental rtl8139 driver from Donald Becker, +some versions of which appeared in 2.2.x and 2.3.x kernels. The +RTL-8139 is a very low-cost Fast Ethernet chip, which makes it very +popular. + +The step from 2.2.x to 2.4.x kernels brings many new features to Linux +device drivers. Features for MMIO resources, a standard hot-plug API, +and other interfaces are now becoming requirements, as drivers move +off the x86 platform. With that in mind, I have begun updating the +RTL-8139 driver to current 2.3.x (2.4) kernel standards and APIs, and +fixing the problems that users have been encountering. + + + +Features of 8139too +------------------- +[note - this list intended for people familiar with kernel drivers] + +** 100% MMIO, for full speed operation. All users (so far) have +reported performance increases over their existing RTL drivers. + +** Multi-platform support: x86, Alpha, PPC, ... + +** Use proper SMP spinlocking, fixing SMP interrupt bugs, making the +driver portable to non-x86 SMP platforms in the process. + +** Use new PCI driver API for seamless, low-maintenance hot-plug support + +** Several bugs fixes from original rtl8139 1.08r (October 5, 1999), +including the very common "transmit timeout" problem. + +* Use new resource allocation API, required for hot-plug support +* Use new register read/write macros +* initcall support (module_init/exit) +* vastly improved debug tracing support +* code formatting in many places for readability +* use new init_etherdev() facilities + +...and probably some other less important changes which I forgot. + + + +Installation +------------ + +OPTION 1: Build inside kernel tree (into kernel image, or as module) + + (overwrite 8139too driver in kernel tree with different version) + 1) cp 8139too.c $my_source_tree/drivers/net/8139too.c + +OPTION 2: Build outside kernel tree + + Use the included Makefile. + + + +Tested Adapters +--------------- +AOpen ALN-325C +KTI KF-230TX +KTI KF-230TX/2 + +(please add your adapter model to this list) + + + +Status of Platform Support +-------------------------- + +(see errata below for details) + +x86: tested, stable +Alpha AXP: tested, stable +PowerPC: tested, unstable +Sparc64: not tested + + + +Special Thanks +-------------- +The following people contributed invaluable testing time, feedback +and/or patches during the development of this driver. Thanks to all +of them. + +Donald Becker, Alan Cox, Richard Stallman, Linus Torvalds - inspiration + +Alan Cox, Gerard Roudier - insight on posted MMIO writes + +Martin Mares - code review + +Tigran Aivazian - testing, code review, and a bug fix + +Chmouel Boudjnah, Alexander Dietrich, Oleg Drokin, +James Fidell, Taso Hatzi, Peter K - intrepid test team + +And thanks to every supporter free software. + + + +Known Bugs / Errata / To-Do +--------------------------- +The following issues are known, and are actively being pursued. Patches +to resolve these issues is welcome. If a problem occurs which is not in +the list, please report it. That's why we do beta releases, after all... + + + +1) Work with Donald to merge fixes and updates into his driver. + +2) 2.2.x COMPATIBILITY SUPPORT IS BROKEN. DO NOT USE IT. +It is included only for enterprising hackers willing to help fix it. + +3) PPC platform has stability problems. + +4) Sparc64 platform not tested at all. + +5) Identify and fix "rx wedge" when ping flooded. + +7) N-Way auto-negotiation is known to fail in some cases. This problem +also occurs in the rtl8139 driver in kernels 2.2.x/2.3.x. Solution: +Following technique in sunhme and sunbmac, use a kernel timer to +manually perform autonegotiation in case the network or card cannot do +it automatically. (patches welcome) + +8) Much improved command line / module parameter setup. (patches and +suggestions welcome) + +9) Better documentation. (patches welcome) + +10) User-mode (or maybe optional /proc) diagnostics program. + + + + +Change History +-------------- +Version 0.9.3.3.2 - Feb 22, 2000 - second public beta release + +* Begin integration of Daniel Kobras' MMIO flush patch (disabled for now) +* Softnet logic updates to fix bugs and improve performance +* Dynamic sizing of I/O resources (0x80 for older chips, 0xFF for newer ones) +* Remove bogus SiS entries from PCI probe table +* Add support for cards + "Delta Electronics 8139 10/100BaseTX" + "Addtron Technolgy 8139 10/100BaseTX" +* Fix major bug with rx ring buffer size (also present in rtl8139.c 1.08r) +* PCI DMA mapping by Dave Miller +* Complete rewrite of SMP locking logic +* Hotplug support +* Call rtl8139_hw_start from rtl8139_open, and remove duplicated code + from rtl8139_open +* Reset NWay registers to sane defaults on rtl8139_open/hw_start +* Miscellaneous code cleanup + +Version 0.7.0 - Feb 7, 2000 - first public beta release + + +[EOF] + diff -u --recursive --new-file v2.3.47/linux/Documentation/networking/fore200e.txt linux/Documentation/networking/fore200e.txt --- v2.3.47/linux/Documentation/networking/fore200e.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/fore200e.txt Mon Feb 21 16:32:27 2000 @@ -0,0 +1,55 @@ + +Fore PCA-200E/SBA-200E ATM NIC Firmware Copyright Notice +-------------------------------------------------------- + +Please read the fore200e_firmware_copyright file present +in the linux/drivers/atm directory for details and restrictions. + + +Firmware Updates +---------------- + +The FORE Systems 200E-series driver is shipped with firmware data being +uploaded to the ATM adapters at system boot time or at module loading time. +The supplied firmware images should work with all adapters. + +However, if you encounter problems (firmware doesn't start or the driver +is unable to read PROM data), you may consider trying another firmware +version. Alternative binary firmware images can be found somewhere on the +ForeThough CD-ROM supplied with your adapter by FORE Systems. + +You can also get the latest firmware images from FORE Systems at +http://www.fore.com. Register TACTics Online and go to +the 'software updates' pages. The firmware binaries are part of +the various ForeThough software distributions. + +Notice that different versions of the PCA-200E firmware exist, depending +on the endianess of the host architecture. The driver is shipped with +both little and big endian PCA firmware images. + +Name and location of the new firmware images can be set at kernel +configuration time. + + +Driver Rebuilding +----------------- + +1. Copy the new firmware binary files (with .bin, .bin1 or .bin2 suffix) + to some directory, such as linux/drivers/atm. + +2. Reconfigure your kernel to set the new firmware name and location. + Expected pathnames are absolute or relative to the drivers/atm directory. + +3. Delete the files drivers/atm/fore200e_pca_fw.[co] and/or fore200e_sba_fw.[co] + to ensure that the new firmware will be used when rebuilding the kernel or + the module. + +4. Rebuild and re-install your kernel or your module. + + +Feedback +-------- + +Feedback is welcome. Please send success stories/bug reports/ +patches/improvement/comments/flames to . + diff -u --recursive --new-file v2.3.47/linux/Documentation/networking/tulip.txt linux/Documentation/networking/tulip.txt --- v2.3.47/linux/Documentation/networking/tulip.txt Wed May 20 18:54:34 1998 +++ linux/Documentation/networking/tulip.txt Fri Feb 25 15:16:37 2000 @@ -1,110 +1,144 @@ Tulip Ethernet Card Driver + Maintained by Jeff Garzik The Tulip driver is developed by Donald Becker and changed by -Takashi Manabe. This driver is designed to work with PCI Ethernet -cards which use the DECchip DC21x4x family. This driver hopefully -works with all of 1.2.x and 1.3.x kernels, but I tested only -with 1.2.13, 1.3.39, 1.3.49, 1.3.52, 1.3.57 and later. - -Hopefully, the de4x5.c driver will support all cards supported -by the tulip.c driver. However, the SMC's 9332dst card and some -cards do not work with the de4x5.c driver. So, if your card is -not a 9332dst, please try the de4x5.c driver first. - -Success List -============ - -+-------------------------------------+-----------+-------------+ -|vendor/card |chip |system | -+-------------------------------------+-----------+-------------+ -|SMC | | | -| EtherPower 10 PCI(8432T/8432BT) |21040/21041|Pentium | -+-------------------------------------+-----------+-------------+ -|SMC | | | -| EtherPower 10/100 PCI(9332DST) |21140 |Pentium/UDB | -+-------------------------------------+-----------+-------------+ -|DEC | | | -| EtherWorks 100/10 PCI(DE500-XA) |21140 |Pentium | -+-------------------------------------+-----------+-------------+ -|DEC | | | -| EtherWorks 10 PCI(DE450) |21041 |Pentium | -+-------------------------------------+-----------+-------------+ -|DEC | | | -| QSILVER's |21040 |UDB | -+-------------------------------------+-----------+-------------+ -|ZNYX | | | -| 312 etherarray |21040 |Pentium | -+-------------------------------------+-----------+-------------+ -|Allied Telesis | | | -| LA100PCI-T |21140 |Pentium/UDB | -+-------------------------------------+-----------+-------------+ -|Danpex ('Planet Japan' in Japan?) | | | -| EN-9400 |21040 |Pentium | -+-------------------------------------+-----------+-------------+ -|Cogent | | | -| EM110 |21140 |Pentium | -+-------------------------------------+-----------+-------------+ - -Pentium: PCI machine with Pentium CPU -UDB: Universal Desktop Box(aka Multia) with Alpha 21066 CPU - -Known bug(s) -============ -This driver's media detection is very simple and sometimes -it causes serious problem. The driver automatically switches -media when it causes timeout. If you want to specify or to fix -a media; - -- Modify TULIP_PORT in tulip.c, line 33. -- Uncomment the definition of TULIP_FIX_PORT in tulip.c, line 40. - -or - -- Use patched ifconfig command and specify 'link='. The patch - against ifconfig.c in net-tools-1.3.50-BETA6e is included in - this file. +Takashi Manabe and a cast of thousands. -Thanks + This driver is for the Digital "Tulip" Ethernet adapter interface. + It should work with most DEC 21*4*-based chips/ethercards, as well as + with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX. + + The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + Center of Excellence in Space Data and Information Sciences + Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + Additional information available at + http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html + + Theory of Operation + +Board Compatibility +=================== + +This device driver is designed for the DECchip "Tulip", Digital's +single-chip ethernet controllers for PCI. Supported members of the family +are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike +chips from Lite-On, Macronics, ASIX, Compex and other listed below are also +supported. + +These chips are used on at least 140 unique PCI board designs. The great +number of chips and board designs supported is the reason for the +driver size and complexity. Almost of the increasing complexity is in the +board configuration and media selection code. There is very little +increasing in the operational critical path length. + +Board-specific settings +======================= + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS preferably should assign the +PCI INTA signal to an otherwise unused system IRQ line. + +Some boards have EEPROMs tables with default media entry. The factory default +is usually "autoselect". This should only be overridden when using +transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!) +for forcing full-duplex when used with old link partners that do not do +autonegotiation. + +Driver operation +================ + +Ring buffers +------------ + +The Tulip can use either ring buffers or lists of Tx and Rx descriptors. +This driver uses statically allocated rings of Rx and Tx descriptors, set at +compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs +for the Rx ring buffers at open() time and passes the skb->data field to the +Tulip as receive data buffers. When an incoming frame is less than +RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is +copied to the new skbuff. When the incoming frame is larger, the skbuff is +passed directly up the protocol stack and replaced by a newly allocated +skbuff. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. For small frames the copying cost is negligible (esp. considering +that we are pre-loading the cache with immediately useful header +information). For large frames the copying cost is non-trivial, and the +larger copy might flush the cache of useful data. A subtle aspect of this +choice is that the Tulip only receives into longword aligned buffers, thus +the IP header at offset 14 isn't longword aligned for further processing. +Copied frames are put into the new skbuff at an offset of "+2", thus copying +has the beneficial effect of aligning the IP header and preloading the +cache. + +Synchronization +--------------- +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and other software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'tp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so +we can't avoid the interrupt overhead by having the Tx routine reap the Tx +stats.) After reaping the stats, it marks the queue entry as empty by setting +the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the +tx_full and tbusy flags. + +Notes +===== + +Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board. +Greg LaPolla at Linksys provided PNIC and other Linksys boards. +Znyx provided a four-port card for testing. + +References +========== + +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM") +http://www.national.com/pf/DP/DP83840A.html +http://www.asix.com.tw/pmac.htm +http://www.admtek.com.tw/ + +Errata ====== -o becker@CESDIS.gsfc.nasa.gov (author of the tulip.c driver) -o davies@wanton.lkg.dec.com (author of the de4x5.c driver) +The old DEC databooks were light on details. +The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last +register of the set CSR12-15 written. Hmmm, now how is that possible? + +The DEC SROM format is very badly designed not precisely defined, leading to +part of the media selection junkheap below. Some boards do not have EEPROM +media tables and need to be patched up. Worse, other boards use the DEC +design kit media table when it isn't correct for their board. + +We cannot use MII interrupts because there is no defined GPIO pin to attach +them. The MII transceiver status is polled using an kernel timer. + + +Source tree tour +---------------- +The following is a list of files comprising the Tulip ethernet driver in +drivers/net/tulip subdirectory. + +21142.c - 21142-specific h/w interaction +eeprom.c - EEPROM reading and parsing +interrupt.c - Interrupt handler +media.c - Media selection and MII support +pnic.c - PNIC-specific h/w interaction +timer.c - Main driver timer, and misc h/w timers +tulip.h - Private driver header +tulip_core.c - Driver core (a.k.a. where "everything else" goes) + + -o siekas@mailhost.tcs.tulane.edu +[EOF] -o jheiss@calvin.caltech.edu (providing information about smc8432 card) -o goto@plathome.co.jp (lending me a DE450 card) -o ted@physics.ucsb.edu -o pmheuvel@xs4all.nl -o hjl@lucon.org (EN-9400) -o niles@axp745.gsfc.nasa.gov (ZNYX312) -o pkc@scs.carleton.ca (EM110) -o and testers... - ------------------------------------------------------------------------ -*** ifconfig.c-dist Wed Jan 17 07:25:36 1996 ---- ifconfig.c Tue Apr 9 15:24:25 1996 -*************** -*** 765,770 **** ---- 766,786 ---- - continue; - } - ifr.ifr_map.irq = atoi(*spp); -+ if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) { -+ fprintf(stderr, "SIOCSIFMAP: %s\n", strerror(errno)); -+ goterr = 1; -+ } -+ spp++; -+ continue; -+ } -+ -+ if (!strcmp(*spp, "link")) { -+ if (*++spp == NULL) usage(); -+ if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) { -+ goterr = 1; -+ continue; -+ } -+ ifr.ifr_map.port = atoi(*spp); - if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0) { - fprintf(stderr, "SIOCSIFMAP: %s\n", strerror(errno)); - goterr = 1; diff -u --recursive --new-file v2.3.47/linux/Documentation/networking/wavelan.txt linux/Documentation/networking/wavelan.txt --- v2.3.47/linux/Documentation/networking/wavelan.txt Thu Aug 26 13:05:34 1999 +++ linux/Documentation/networking/wavelan.txt Mon Feb 21 20:51:51 2000 @@ -1,41 +1,73 @@ -Sun Jul 2 01:38:33 EST 1995 + The Wavelan drivers saga + ------------------------ - As the date above certify, this ``readme'' is mostly -obsolete. Please read release notes and change list in -driver/net/wavelan.p.h, and consult my web page at : - http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html - - Jean - -1. At present the driver autoprobes for a WaveLAN card only at I/O address - 0x390. The version of the card that I use (NCR) supports four I/O addresses - (selectable via a pair of DIP switches). If you want the driver to - autoprobe a different subset of the four valid addresses then you will need - to edit .../drivers/net/wavelan.c (near line 714) and change the - initialisation of the `iobase[]' array. Normally, I use a LILO - configuration file directive to obviate the need for autoprobing entirely, - a course of action I heartily recommend. - -2. By default, the driver uses the Network ID (NWID) stored in the card's - Parameter Storage Area (PSA). However, the PSA NWID can be overridden by a - value passed explicitly as the third numeric argument to LILO's "ether=" - directive, either at the LILO prompt at boot time or within LILO's - configuration file. - For example, the following line from such a LILO configuration file would - auto-configure the IRQ value, set the I/O base to 0x390 and set the NWID to - 0x4321, all on a WaveLAN card labelled "eth0": - - .. - append ="ether=0,0x390,0x4321,eth0" - .. - -3. The driver uses the IRQ stored in the card's PSA. - To change this you will need to use the configuration/setup software that - accompanies each WaveLAN device. Yes, the driver should use the value passed - in via LILO and it will, just as soon as I can work out why that part of the - code doesn't work :-(. + By Jean Tourrilhes -4. If you encounter any problems send me some email. + The Wavelan is a Radio network adapter designed by +Lucent. Under this generic name is hidden quite a variety of hardware, +and many Linux driver to support it. + The get the full story on Wireless LANs, please consult : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ + +"wavelan" driver (old ISA Wavelan) +---------------- + o Config : Network device -> Wireless LAN -> AT&T WaveLAN + o Location : .../drivers/net/wavelan* + o in-line doc : .../drivers/net/wavelan.p.h + o on-line doc : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + + This is the driver for the ISA version of the first generation +of the Wavelan, now discontinued. The device is 2 Mb/s, composed of a +Intel 82586 controler and a Lucent Modem, and is NOT 802.11 compliant. + The driver has been tested with the following hardware : + o Wavelan ISA 915 MHz (full length ISA card) + o Wavelan ISA 915 MHz 2.0 (half length ISA card) + o Wavelan ISA 2.4 GHz (full length ISA card, fixed frequency) + o Wavelan ISA 2.4 GHz 2.0 (half length ISA card, frequency selectable) + o Above cards with the optional DES encryption feature + +"wavelan_cs" driver (old Pcmcia Wavelan) +------------------- + o Config : Network device -> PCMCIA network -> + Pcmcia Wireless LAN -> AT&T/Lucent WaveLAN + o Location : .../drivers/net/pcmcia/wavelan* + o in-line doc : .../drivers/net/pcmcia/wavelan_cs.h + o on-line doc : + http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html + + This is the driver for the PCMCIA version of the first +generation of the Wavelan, now discontinued. The device is 2 Mb/s, +composed of a Intel 82593 controler (totally different from the 82586) +and a Lucent Modem, and NOT 802.11 compatible. + The driver has been tested with the following hardware : + o Wavelan Pcmcia 915 MHz 2.0 (Pcmcia card + separate + modem/antenna block) + o Wavelan Pcmcia 2.4 GHz 2.0 (Pcmcia card + separate + modem/antenna block) + +"wvlan_cs" driver (Wavelan IEEE, GPL) +----------------- + o Config : Not yet in kernel + o Location : Pcmcia package 3.1.10+ + o on-line doc : http://www.fasta.fh-dortmund.de/users/andy/wvlan/ + + This is the driver for the current generation of Wavelan IEEE, +which is 802.11 compatible. Depending on version, it is 2 Mb/s or 11 +Mb/s, with or without encryption, all implemented in Lucent specific +DSP (the Hermes). + This is a GPL full source PCMCIA driver (ISA is just a Pcmcia +card with ISA-Pcmcia bridge). + +"wavelan2_cs" driver (Wavelan IEEE, binary) +-------------------- + o Config : Not yet in kernel + o Location : ftp://sourceforge.org/pcmcia/contrib/ + + This driver support exactly the same hardware as the previous +driver, the main difference is that it is based on a binary library +and supported by Lucent. -Good luck, -Bruce Janson (bruce@cs.usyd.edu.au) + I hope it clears the confusion ;-) + + Jean diff -u --recursive --new-file v2.3.47/linux/Documentation/parport-lowlevel.txt linux/Documentation/parport-lowlevel.txt --- v2.3.47/linux/Documentation/parport-lowlevel.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/parport-lowlevel.txt Thu Feb 24 10:30:25 2000 @@ -0,0 +1,1490 @@ +PARPORT interface documentation +------------------------------- + +Time-stamp: <2000-02-24 13:30:20 twaugh> + +Described here are the following functions: + +Global functions: + parport_register_driver + parport_unregister_driver + parport_enumerate + parport_register_device + parport_unregister_device + parport_claim + parport_claim_or_block + parport_release + parport_yield + parport_yield_blocking + parport_wait_peripheral + parport_poll_peripheral + parport_wait_event + parport_negotiate + parport_read + parport_write + parport_open + parport_close + parport_device_id + parport_device_num + parport_device_coords + parport_find_class + parport_find_device + parport_set_timeout + +Port functions (can be overridden by low-level drivers): + SPP: + port->ops->read_data + port->ops->write_data + port->ops->read_status + port->ops->read_control + port->ops->write_control + port->ops->frob_control + port->ops->enable_irq + port->ops->disable_irq + port->ops->data_forward + port->ops->data_reverse + + EPP: + port->ops->epp_write_data + port->ops->epp_read_data + port->ops->epp_write_addr + port->ops->epp_read_addr + + ECP: + port->ops->ecp_write_data + port->ops->ecp_read_data + port->ops->ecp_write_addr + + Other: + port->ops->nibble_read_data + port->ops->byte_read_data + port->ops->compat_write_data + +The parport subsystem comprises 'parport' (the core port-sharing +code), and a variety of low-level drivers that actually do the port +accesses. Each low-level driver handles a particular style of port +(PC, Amiga, and so on). + +The parport interface to the device driver author can be broken down +into global functions and port functions. + +The global functions are mostly for communicating between the device +driver and the parport subsystem: acquiring a list of available ports, +claiming a port for exclusive use, and so on. They also include +'generic' functions for doing standard things that will work on any +IEEE 1284-capable architecture. + +The port functions are provided by the low-level drivers, although the +core parport module provides generic 'defaults' for some routines. +The port functions can be split into three groups: SPP, EPP, and ECP. + +SPP (Standard Parallel Port) functions modify so-called 'SPP' +registers: data, status, and control. The hardware may not actually +have registers exactly like that, but the PC does and this interface is +modelled after common PC implementations. Other low-level drivers may +be able to emulate most of the functionality. + +EPP (Enhanced Parallel Port) functions are provided for reading and +writing in IEEE 1284 EPP mode, and ECP (Extended Capabilities Port) +functions are used for IEEE 1284 ECP mode. (What about BECP? Does +anyone care?) + +Hardware assistance for EPP and/or ECP transfers may or may not be +available, and if it is available it may or may not be used. If +hardware is not used, the transfer will be software-driven. In order +to cope with peripherals that only tenuously support IEEE 1284, a +low-level driver specific function is provided, for altering 'fudge +factors'. + +GLOBAL FUNCTIONS +---------------- + +parport_register_driver - register a device driver with parport +----------------------- + +SYNOPSIS + +#include + +struct parport_driver { + const char *name; + void (*attach) (struct parport *); + void (*detach) (struct parport *); + struct parport_driver *next; +}; +int parport_register_driver (struct parport_driver *driver); + +DESCRIPTION + +In order to be notified about parallel ports when they are detected, +parport_register_driver should be called. Your driver will +immediately be notified of all ports that have already been detected, +and of each new port as low-level drivers are loaded. + +A 'struct parport_driver' contains the textual name of your driver, +a pointer to a function to handle new ports, and a pointer to a +function to handle ports going away due to a low-level driver +unloading. Ports will only be detached if they are not being used +(i.e. there are no devices registered on them). + +The visible parts of the 'struct parport *' argument given to +attach/detach are: + +struct parport +{ + struct parport *next; /* next parport in list */ + const char *name; /* port's name */ + unsigned int modes; /* bitfield of hardware modes */ + struct parport_device_info probe_info; + /* IEEE1284 info */ + int number; /* parport index */ + struct parport_operations *ops; + ... +}; + +There are other members of the structure, but they should not be +touched. + +The 'modes' member summarises the capabilities of the underlying +hardware. It consists of flags which may be bitwise-ored together: + + PARPORT_MODE_PCSPP IBM PC registers are available, + i.e. functions that act on data, + control and status registers are + probably writing directly to the + hardware. + PARPORT_MODE_TRISTATE The data drivers may be turned off. + This allows the data lines to be used + for reverse (peripheral to host) + transfers. + PARPORT_MODE_COMPAT The hardware can assist with + compatibility-mode (printer) + transfers, i.e. compat_write_block. + PARPORT_MODE_EPP The hardware can assist with EPP + transfers. + PARPORT_MODE_ECP The hardware can assist with ECP + transfers. + PARPORT_MODE_DMA The hardware can use DMA, so you might + want to pass ISA DMA-able memory + (i.e. memory allocated using the + GFP_DMA flag with kmalloc) to the + low-level driver in order to take + advantage of it. + +There may be other flags in 'modes' as well. + +The contents of 'modes' is advisory only. For example, if the +hardware is capable of DMA, and PARPORT_MODE_DMA is in 'modes', it +doesn't necessarily mean that DMA will always be used when possible. +Similarly, hardware that is capable of assisting ECP transfers won't +necessarily be used. + +RETURN VALUE + +Zero on success, otherwise an error code. + +ERRORS + +None. (Can it fail? Why return int?) + +EXAMPLE + +static void lp_attach (struct parport *port) +{ + ... + private = kmalloc (...); + dev[count++] = parport_register_device (...); + ... +} + +static void lp_detach (struct parport *port) +{ + ... +} + +static struct parport_driver lp_driver = { + "lp", + lp_attach, + lp_detach, + NULL /* always put NULL here */ +}; + +int lp_init (void) +{ + ... + if (parport_register_driver (&lp_driver)) { + /* Failed; nothing we can do. */ + return -EIO; + } + ... +} + +SEE ALSO + +parport_unregister_driver, parport_register_device, parport_enumerate + +parport_unregister_driver - tell parport to forget about this driver +------------------------- + +SYNOPSIS + +#include + +struct parport_driver { + const char *name; + void (*attach) (struct parport *); + void (*detach) (struct parport *); + struct parport_driver *next; +}; +void parport_unregister_driver (struct parport_driver *driver); + +DESCRIPTION + +This tells parport not to notify the device driver of new ports or of +ports going away. Registered devices belonging to that driver are NOT +unregistered: parport_unregister_device must be used for each one. + +EXAMPLE + +void cleanup_module (void) +{ + ... + /* Stop notifications. */ + parport_unregister_driver (&lp_driver); + + /* Unregister devices. */ + for (i = 0; i < NUM_DEVS; i++) + parport_unregister_device (dev[i]); + ... +} + +SEE ALSO + +parport_register_driver, parport_enumerate + +parport_enumerate - retrieve a list of parallel ports (DEPRECATED) +----------------- + +SYNOPSIS + +#include + +struct parport *parport_enumerate (void); + +DESCRIPTION + +Retrieve the first of a list of valid parallel ports for this machine. +Successive parallel ports can be found using the 'struct parport +*next' element of the 'struct parport *' that is returned. If 'next' +is NULL, there are no more parallel ports in the list. The number of +ports in the list will not exceed PARPORT_MAX. + +RETURN VALUE + +A 'struct parport *' describing a valid parallel port for the machine, +or NULL if there are none. + +ERRORS + +This function can return NULL to indicate that there are no parallel +ports to use. + +EXAMPLE + +int detect_device (void) +{ + struct parport *port; + + for (port = parport_enumerate (); + port != NULL; + port = port->next) { + /* Try to detect a device on the port... */ + ... + } + } + + ... +} + +NOTES + +parport_enumerate is deprecated; parport_register_driver should be +used instead. + +SEE ALSO + +parport_register_driver, parport_unregister_driver + +parport_register_device - register to use a port +----------------------- + +SYNOPSIS + +#include + +typedef int (*preempt_func) (void *handle); +typedef void (*wakeup_func) (void *handle); +typedef int (*irq_func) (int irq, void *handle, struct pt_regs *); + +struct pardevice *parport_register_device(struct parport *port, + const char *name, + preempt_func preempt, + wakeup_func wakeup, + irq_func irq, + int flags, + void *handle); + +DESCRIPTION + +Use this function to register your device driver on a parallel port +('port'). Once you have done that, you will be able to use +parport_claim and parport_release in order to use the port. + +This function will register three callbacks into your driver: +'preempt', 'wakeup' and 'irq'. Each of these may be NULL in order to +indicate that you do not want a callback. + +When the 'preempt' function is called, it is because another driver +wishes to use the parallel port. The 'preempt' function should return +non-zero if the parallel port cannot be released yet -- if zero is +returned, the port is lost to another driver and the port must be +re-claimed before use. + +The 'wakeup' function is called once another driver has released the +port and no other driver has yet claimed it. You can claim the +parallel port from within the 'wakeup' function (in which case the +claim is guaranteed to succeed), or choose not to if you don't need it +now. + +If an interrupt occurs on the parallel port your driver has claimed, +the 'irq' function will be called. (Write something about shared +interrupts here.) + +The 'handle' is a pointer to driver-specific data, and is passed to +the callback functions. + +'flags' may be a bitwise combination of the following flags: + + Flag Meaning + PARPORT_DEV_EXCL The device cannot share the parallel port at all. + Use this only when absolutely necessary. + +The typedefs are not actually defined -- they are only shown in order +to make the function prototype more readable. + +The visible parts of the returned 'struct pardevice' are: + +struct pardevice { + struct parport *port; /* Associated port */ + void *private; /* Device driver's 'handle' */ + ... +}; + +RETURN VALUE + +A 'struct pardevice *': a handle to the registered parallel port +device that can be used for parport_claim, parport_release, etc. + +ERRORS + +A return value of NULL indicates that there was a problem registering +a device on that port. + +EXAMPLE + +static int preempt (void *handle) +{ + if (busy_right_now) + return 1; + + must_reclaim_port = 1; + return 0; +} + +static void wakeup (void *handle) +{ + struct toaster *private = handle; + struct pardevice *dev = private->dev; + if (!dev) return; /* avoid races */ + + if (want_port) + parport_claim (dev); +} + +static int toaster_detect (struct toaster *private, struct parport *port) +{ + private->dev = parport_register_device (port, "toaster", preempt, + wakeup, NULL, 0, + private); + if (!private->dev) + /* Couldn't register with parport. */ + return -EIO; + + must_reclaim_port = 0; + busy_right_now = 1; + parport_claim_or_block (private->dev); + ... + /* Don't need the port while the toaster warms up. */ + busy_right_now = 0; + ... + busy_right_now = 1; + if (must_reclaim_port) { + parport_claim_or_block (private->dev); + must_reclaim_port = 0; + } + ... +} + +SEE ALSO + +parport_unregister_device, parport_claim + +parport_unregister_device - finish using a port +------------------------- + +SYNPOPSIS + +#include + +void parport_unregister_device (struct pardevice *dev); + +DESCRIPTION + +This function is the opposite of parport_register_device. After using +parport_unregister_device, 'dev' is no longer a valid device handle. + +You should not unregister a device that is currently claimed, although +if you do it will be released automatically. + +EXAMPLE + + ... + kfree (dev->private); /* before we lose the pointer */ + parport_unregister_device (dev); + ... + +SEE ALSO + +parport_unregister_driver + +parport_claim, parport_claim_or_block - claim the parallel port for a device +------------------------------------- + +SYNOPSIS + +#include + +int parport_claim (struct pardevice *dev); +int parport_claim_or_block (struct pardevice *dev); + +DESCRIPTION + +These functions attempt to gain control of the parallel port on which +'dev' is registered. 'parport_claim' does not block, but +'parport_claim_or_block' may do. (Put something here about blocking +interruptibly or non-interruptibly.) + +You should not try to claim a port that you have already claimed. + +RETURN VALUE + +A return value of zero indicates that the port was successfully +claimed, and the caller now has possession of the parallel port. + +If 'parport_claim_or_block' blocks before returning successfully, the +return value is positive. + +ERRORS + + -EAGAIN The port is unavailable at the moment, but another attempt + to claim it may succeed. + +SEE ALSO + +parport_release + +parport_release - release the parallel port +--------------- + +SYNOPSIS + +#include + +void parport_release (struct pardevice *dev); + +DESCRIPTION + +Once a parallel port device has been claimed, it can be released using +'parport_release'. It cannot fail, but you should not release a +device that you do not have possession of. + +EXAMPLE + +static size_t write (struct pardevice *dev, const void *buf, + size_t len) +{ + ... + written = dev->port->ops->write_ecp_data (dev->port, buf, + len); + parport_release (dev); + ... +} + + +SEE ALSO + +change_mode, parport_claim, parport_claim_or_block, parport_yield + +parport_yield, parport_yield_blocking - temporarily release a parallel port +------------------------------------- + +SYNOPSIS + +#include + +int parport_yield (struct pardevice *dev) +int parport_yield_blocking (struct pardevice *dev); + +DESCRIPTION + +When a driver has control of a parallel port, it may allow another +driver to temporarily 'borrow' it. 'parport_yield' does not block; +'parport_yield_blocking' may do. + +RETURN VALUE + +A return value of zero indicates that the caller still owns the port +and the call did not block. + +A positive return value from 'parport_yield_blocking' indicates that +the caller still owns the port and the call blocked. + +A return value of -EAGAIN indicates that the caller no longer owns the +port, and it must be re-claimed before use. + +ERRORS + + -EAGAIN Ownership of the parallel port was given away. + +SEE ALSO + +parport_release + +parport_wait_peripheral - wait for status lines, up to 35ms +----------------------- + +SYNOPSIS + +#include + +int parport_wait_peripheral (struct parport *port, + unsigned char mask, + unsigned char val); + +DESCRIPTION + +Wait for the status lines in mask to match the values in val. + +RETURN VALUE + + -EINTR a signal is pending + 0 the status lines in mask have values in val + 1 timed out while waiting (35ms elapsed) + +SEE ALSO + +parport_poll_peripheral + +parport_poll_peripheral - wait for status lines, in usec +----------------------- + +SYNOPSIS + +#include + +int parport_poll_peripheral (struct parport *port, + unsigned char mask, + unsigned char val, + int usec); + +DESCRIPTION + +Wait for the status lines in mask to match the values in val. + +RETURN VALUE + + -EINTR a signal is pending + 0 the status lines in mask have values in val + 1 timed out while waiting (usec microseconds have elapsed) + +SEE ALSO + +parport_wait_peripheral + +parport_wait_event - wait for an event on a port +------------------ + +SYNOPSIS + +#include + +int parport_wait_event (struct parport *port, signed long timeout) + +DESCRIPTION + +Wait for an event (e.g. interrupt) on a port. The timeout is in +jiffies. + +RETURN VALUE + + 0 success + <0 error (exit as soon as possible) + >0 timed out + +parport_negotiate - perform IEEE 1284 negotiation +----------------- + +SYNOPSIS + +#include + +int parport_negotiate (struct parport *, int mode); + +DESCRIPTION + +Perform IEEE 1284 negotiation. + +RETURN VALUE + + 0 handshake OK; IEEE 1284 peripheral and mode available + -1 handshake failed; peripheral not compliant (or none present) + 1 handshake OK; IEEE 1284 peripheral present but mode not + available + +SEE ALSO + +parport_read, parport_write + +parport_read - read data from device +------------ + +SYNOPSIS + +#include + +ssize_t parport_read (struct parport *, void *buf, size_t len); + +DESCRIPTION + +Read data from device in current IEEE 1284 transfer mode. This only +works for modes that support reverse data transfer. + +RETURN VALUE + +If negative, an error code; otherwise the number of bytes transferred. + +SEE ALSO + +parport_write, parport_negotiate + +parport_write - write data to device +------------- + +SYNOPSIS + +#include + +ssize_t parport_write (struct parport *, const void *buf, size_t len); + +DESCRIPTION + +Write data to device in current IEEE 1284 transfer mode. This only +works for modes that support forward data transfer. + +RETURN VALUE + +If negative, an error code; otherwise the number of bytes transferred. + +SEE ALSO + +parport_read, parport_negotiate + +parport_open - register device for particular device number +------------ + +SYNOPSIS + +#include + +struct pardevice *parport_open (int devnum, const char *name, + int (*pf) (void *), + void (*kf) (void *), + void (*irqf) (int, void *, + struct pt_regs *), + int flags, void *handle); + +DESCRIPTION + +This is like parport_register_device but takes a device number instead +of a pointer to a struct parport. + +RETURN VALUE + +See parport_register_device. If no device is associated with devnum, +NULL is returned. + +SEE ALSO + +parport_register_device, parport_device_num + +parport_close - unregister device for particular device number +------------- + +SYNOPSIS + +#include + +void parport_close (struct pardevice *dev); + +DESCRIPTION + +This is the equivalent of parport_unregister_device for parport_open. + +SEE ALSO + +parport_unregister_device, parport_open + +parport_device_id - obtain IEEE 1284 Device ID +----------------- + +SYNOPSIS + +#include + +ssize_t parport_device_id (int devnum, char *buffer, size_t len); + +DESCRIPTION + +Obtains the IEEE 1284 Device ID associated with a given device. + +RETURN VALUE + +If negative, an error code; otherwise, the number of bytes of buffer +that contain the device ID. The format of the device ID is as +follows: + +[length][ID] + +The first two bytes indicate the inclusive length of the entire Device +ID, and are in big-endian order. The ID is a sequence of pairs of the +form: + +key:value; + +NOTES + +Many devices have ill-formed IEEE 1284 Device IDs. + +SEE ALSO + +parport_find_class, parport_find_device, parport_device_num + +parport_device_num - convert device coordinates to device number +------------------ + +SYNOPSIS + +#include + +int parport_device_num (int parport, int mux, int daisy); + +DESCRIPTION + +Convert between device coordinates (port, multiplexor, daisy chain +address) and device number (zero-based). + +RETURN VALUE + +Device number, or -1 if no device at given coordinates. + +SEE ALSO + +parport_device_coords, parport_open, parport_device_id + +parport_device_coords - convert device number to device coordinates +------------------ + +SYNOPSIS + +#include + +int parport_device_coords (int devnum, int *parport, int *mux, + int *daisy); + +DESCRIPTION + +Convert between device number (zero-based) and device coordinates +(port, multiplexor, daisy chain address). + +RETURN VALUE + +Zero on success, in which case the coordinates are (*parport, *mux, +*daisy). + +SEE ALSO + +parport_device_num, parport_open, parport_device_id + +parport_find_class - find a device by its class +------------------ + +SYNOPSIS + +#include + +typedef enum { + PARPORT_CLASS_LEGACY = 0, /* Non-IEEE1284 device */ + PARPORT_CLASS_PRINTER, + PARPORT_CLASS_MODEM, + PARPORT_CLASS_NET, + PARPORT_CLASS_HDC, /* Hard disk controller */ + PARPORT_CLASS_PCMCIA, + PARPORT_CLASS_MEDIA, /* Multimedia device */ + PARPORT_CLASS_FDC, /* Floppy disk controller */ + PARPORT_CLASS_PORTS, + PARPORT_CLASS_SCANNER, + PARPORT_CLASS_DIGCAM, + PARPORT_CLASS_OTHER, /* Anything else */ + PARPORT_CLASS_UNSPEC, /* No CLS field in ID */ + PARPORT_CLASS_SCSIADAPTER +} parport_device_class; + +int parport_find_class (parport_device_class cls, int from); + +DESCRIPTION + +Find a device by class. The search starts from device number from+1. + +RETURN VALUE + +The device number of the next device in that class, or -1 if no such +device exists. + +NOTES + +Example usage: + +int devnum = -1; +while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, devnum)) != -1) { + struct pardevice *dev = parport_open (devnum, ...); + ... +} + +SEE ALSO + +parport_find_device, parport_open, parport_device_id + +parport_find_device - find a device by its class +------------------ + +SYNOPSIS + +#include + +int parport_find_device (const char *mfg, const char *mdl, int from); + +DESCRIPTION + +Find a device by vendor and model. The search starts from device +number from+1. + +RETURN VALUE + +The device number of the next device matching the specifications, or +-1 if no such device exists. + +NOTES + +Example usage: + +int devnum = -1; +while ((devnum = parport_find_device ("IOMEGA", "ZIP+", devnum)) != -1) { + struct pardevice *dev = parport_open (devnum, ...); + ... +} + +SEE ALSO + +parport_find_class, parport_open, parport_device_id + +parport_set_timeout - set the inactivity timeout +------------------- + +SYNOPSIS + +#include + +long parport_set_timeout (struct pardevice *dev, long inactivity); + +DESCRIPTION + +Set the inactivity timeout, in jiffies, for a registered device. The +previous timeout is returned. + +RETURN VALUE + +The previous timeout, in jiffies. + +NOTES + +Some of the port->ops functions for a parport may take time, owing to +delays at the peripheral. After the peripheral has not responded for +'inactivity' jiffies, a timeout will occur and the blocking function +will return. + +A timeout of 0 jiffies is a special case: the function must do as much +as it can without blocking or leaving the hardware in an unknown +state. If port operations are performed from within an interrupt +handler, for instance, a timeout of 0 jiffies should be used. + +Once set for a registered device, the timeout will remain at the set +value until set again. + +SEE ALSO + +port->ops->xxx_read/write_yyy + +PORT FUNCTIONS +-------------- + +The functions in the port->ops structure (struct parport_operations) +are provided by the low-level driver responsible for that port. + +port->ops->read_data - read the data register +-------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + unsigned char (*read_data) (struct parport *port); + ... +}; + +DESCRIPTION + +If port->modes contains the PARPORT_MODE_TRISTATE flag and the +PARPORT_CONTROL_DIRECTION bit in the control register is set, this +returns the value on the data pins. If port->modes contains the +PARPORT_MODE_TRISTATE flag and the PARPORT_CONTROL_DIRECTION bit is +not set, the return value _may_ be the last value written to the data +register. Otherwise the return value is undefined. + +SEE ALSO + +write_data, read_status, write_control + +port->ops->write_data - write the data register +--------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*write_data) (struct parport *port, unsigned char d); + ... +}; + +DESCRIPTION + +Writes to the data register. May have side-effects (a STROBE pulse, +for instance). + +SEE ALSO + +read_data, read_status, write_control + +port->ops->read_status - read the status register +---------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + unsigned char (*read_status) (struct parport *port); + ... +}; + +DESCRIPTION + +Reads from the status register. This is a bitmask: + +- PARPORT_STATUS_ERROR (printer fault, "nFault") +- PARPORT_STATUS_SELECT (on-line, "Select") +- PARPORT_STATUS_PAPEROUT (no paper, "PError") +- PARPORT_STATUS_ACK (handshake, "nAck") +- PARPORT_STATUS_BUSY (busy, "Busy") + +There may be other bits set. + +SEE ALSO + +read_data, write_data, write_control + +port->ops->read_control - read the control register +----------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + unsigned char (*read_control) (struct parport *port); + ... +}; + +DESCRIPTION + +Returns the last value written to the control register (either from +write_control or frob_control). No port access is performed. + +SEE ALSO + +read_data, write_data, read_status, write_control + +port->ops->write_control - write the control register +------------------------ + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*write_status) (struct parport *port, unsigned char s); + ... +}; + +DESCRIPTION + +Writes to the control register. This is a bitmask: + _______ +- PARPORT_CONTROL_STROBE (nStrobe) + _______ +- PARPORT_CONTROL_AUTOFD (nAutoFd) + _____ +- PARPORT_CONTROL_INIT (nInit) + _________ +- PARPORT_CONTROL_SELECT (nSelectIn) + +SEE ALSO + +read_data, write_data, read_status, frob_control + +port->ops->frob_control - write control register bits +----------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*frob_control) (struct parport *port, + unsigned char mask, + unsigned char val); + ... +}; + +DESCRIPTION + +This is equivalent to reading from the control register, masking out +the bits in mask, exclusive-or'ing with the bits in val, and writing +the result to the control register. + +As some ports don't allow reads from the control port, a software copy +of its contents is maintained, so frob_control is in fact only one +port access. + +SEE ALSO + +read_data, write_data, read_status, write_control + +port->ops->enable_irq - enable interrupt generation +--------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*enable_irq) (struct parport *port); + ... +}; + +DESCRIPTION + +The parallel port hardware is instructed to generate interrupts at +appropriate moments, although those moments are +architecture-specific. For the PC architecture, interrupts are +commonly generated on the rising edge of nAck. + +SEE ALSO + +disable_irq + +port->ops->disable_irq - disable interrupt generation +---------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*disable_irq) (struct parport *port); + ... +}; + +DESCRIPTION + +The parallel port hardware is instructed not to generate interrupts. +The interrupt itself is not masked. + +SEE ALSO + +enable_irq + +port->ops->data_forward - enable data drivers +----------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*data_forward) (struct parport *port); + ... +}; + +DESCRIPTION + +Enables the data line drivers, for 8-bit host-to-peripheral +communications. + +SEE ALSO + +data_reverse + +port->ops->data_reverse - tristate the buffer +----------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + void (*data_reverse) (struct parport *port); + ... +}; + +DESCRIPTION + +Places the data bus in a high impedance state, if port->modes has the +PARPORT_MODE_TRISTATE bit set. + +SEE ALSO + +data_forward + +port->ops->epp_write_data - write EPP data +------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*epp_write_data) (struct parport *port, const void *buf, + size_t len, int flags); + ... +}; + +DESCRIPTION + +Writes data in EPP mode, and returns the number of bytes written. + +The 'flags' parameter may be one or more of the following, +bitwise-or'ed together: + +PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and + 32-bit registers. However, if a transfer + times out, the return value may be unreliable. + +SEE ALSO + +epp_read_data, epp_write_addr, epp_read_addr + +port->ops->epp_read_data - read EPP data +------------------------ + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*epp_read_data) (struct parport *port, void *buf, + size_t len, int flags); + ... +}; + +DESCRIPTION + +Reads data in EPP mode, and returns the number of bytes read. + +The 'flags' parameter may be one or more of the following, +bitwise-or'ed together: + +PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and + 32-bit registers. However, if a transfer + times out, the return value may be unreliable. + +SEE ALSO + +epp_write_data, epp_write_addr, epp_read_addr + +port->ops->epp_write_addr - write EPP address +------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*epp_write_addr) (struct parport *port, + const void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Writes EPP addresses (8 bits each), and returns the number written. + +The 'flags' parameter may be one or more of the following, +bitwise-or'ed together: + +PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and + 32-bit registers. However, if a transfer + times out, the return value may be unreliable. + +(Does PARPORT_EPP_FAST make sense for this function?) + +SEE ALSO + +epp_write_data, epp_read_data, epp_read_addr + +port->ops->epp_read_addr - read EPP address +------------------------ + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*epp_read_addr) (struct parport *port, void *buf, + size_t len, int flags); + ... +}; + +DESCRIPTION + +Reads EPP addresses (8 bits each), and returns the number read. + +The 'flags' parameter may be one or more of the following, +bitwise-or'ed together: + +PARPORT_EPP_FAST Use fast transfers. Some chips provide 16-bit and + 32-bit registers. However, if a transfer + times out, the return value may be unreliable. + +(Does PARPORT_EPP_FAST make sense for this function?) + +SEE ALSO + +epp_write_data, epp_read_data, epp_write_addr + +port->ops->ecp_write_data - write a block of ECP data +------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*ecp_write_data) (struct parport *port, + const void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Writes a block of ECP data. The 'flags' parameter is ignored. + +RETURN VALUE + +The number of bytes written. + +SEE ALSO + +ecp_read_data, ecp_write_addr + +port->ops->ecp_read_data - read a block of ECP data +------------------------ + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*ecp_read_data) (struct parport *port, + void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Reads a block of ECP data. The 'flags' parameter is ignored. + +RETURN VALUE + +The number of bytes read. NB. There may be more unread data in a +FIFO. Is there a way of stunning the FIFO to prevent this? + +SEE ALSO + +ecp_write_block, ecp_write_addr + +port->ops->ecp_write_addr - write a block of ECP addresses +------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*ecp_write_addr) (struct parport *port, + const void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Writes a block of ECP addresses. The 'flags' parameter is ignored. + +RETURN VALUE + +The number of bytes written. + +NOTES + +This may use a FIFO, and if so shall not return until the FIFO is empty. + +SEE ALSO + +ecp_read_data, ecp_write_data + +port->ops->nibble_read_data - read a block of data in nibble mode +--------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*nibble_read_data) (struct parport *port, + void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Reads a block of data in nibble mode. The 'flags' parameter is ignored. + +RETURN VALUE + +The number of whole bytes read. + +SEE ALSO + +byte_read_data, compat_write_data + +port->ops->byte_read_data - read a block of data in byte mode +------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*byte_read_data) (struct parport *port, + void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Reads a block of data in byte mode. The 'flags' parameter is ignored. + +RETURN VALUE + +The number of bytes read. + +SEE ALSO + +nibble_read_data, compat_write_data + +port->ops->compat_write_data - write a block of data in compatibility mode +---------------------------- + +SYNOPSIS + +#include + +struct parport_operations { + ... + size_t (*compat_write_data) (struct parport *port, + const void *buf, size_t len, int flags); + ... +}; + +DESCRIPTION + +Writes a block of data in compatibility mode. The 'flags' parameter +is ignored. + +RETURN VALUE + +The number of bytes written. + +SEE ALSO + +nibble_read_data, byte_read_data diff -u --recursive --new-file v2.3.47/linux/Documentation/pci.txt linux/Documentation/pci.txt --- v2.3.47/linux/Documentation/pci.txt Thu Feb 10 17:11:02 2000 +++ linux/Documentation/pci.txt Mon Feb 21 10:59:36 2000 @@ -174,6 +174,8 @@ pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3) pci_find_capability() Find specified capability in device's capability list. +pci_module_init() Inline helper function for ensuring correct + pci_driver initialization and error handling. 7. Miscellaneous hints diff -u --recursive --new-file v2.3.47/linux/Documentation/pm.txt linux/Documentation/pm.txt --- v2.3.47/linux/Documentation/pm.txt Thu Feb 10 17:11:02 2000 +++ linux/Documentation/pm.txt Wed Feb 23 20:05:12 2000 @@ -164,3 +164,154 @@ * access the device hardware until a call to "pm_access" is made. */ typedef int (*pm_callback)(struct pm_dev *dev, pm_request_t rqst, void *data); + +Driver Details +-------------- +This is just a quick Q&A as a stopgap until a real driver writers' +power management guide is available. + +Q: When is a device suspended? + +Devices can be suspended based on direct user request (eg. laptop lid +closes), system power policy (eg. sleep after 30 minutes of console +inactivity), or device power policy (eg. power down device after 5 +minutes of inactivity) + +Q: Must a driver honor a suspend request? + +No, a driver can return -EBUSY from a suspend request and this +will stop the system from suspending. When a suspend request +fails, all suspended devices are resumed and the system continues +to run. Suspend can be retried at a later time. + +Q: Can the driver block suspend/resume requests? + +Yes, a driver can delay its return from a suspend or resume +request until the device is ready to handle requests. It +is advantageous to return as quickly as possible from a +request as suspend/resume are done serially. + +Q: What context is a suspend/resume initiated from? + +A suspend or resume is initiated from a kernel thread context. +It is safe to block, allocate memory, initiate requests +or anything else you can do within the kernel. + +Q: Will requests continue to arrive after a suspend? + +Possibly. It is the driver's responsibility to queue(*), +fail, or drop any requests that arrive after returning +success to a suspend request. It is important that the +driver not access its device until after it receives +a resume request as the device's bus may no longer +be active. + +(*) If a driver queues requests for processing after + resume be aware that the device, network, etc. + might be in a different state than at suspend time. + It's probably better to drop requests unless + the driver is a storage device. + +Q: Do I have to manage bus-specific power management registers + +No. It is the responsibility of the bus driver to manage +PCI, USB, etc. power management registers. The bus driver +or the power management subsystem will also enable any +wake-on functionality that the device has. + +Q: So, really, what do I need to do to support suspend/resume? + +You need to save any device context that would +be lost if the device was powered off and then restore +it at resume time. When ACPI is active, there are +three levels of device suspend states; D1, D2, and D3. +(The suspend state is passed as the "data" argument +to the device callback.) With D3, the device is powered +off and loses all context, D1 and D2 are shallower power +states and require less device context to be saved. To +play it safe, just save everything at suspend and restore +everything at resume. + +Q: Where do I store device context for suspend? + +Anywhere in memory, kmalloc a buffer or store it +in the device descriptor. You are guaranteed that the +contents of memory will be restored and accessible +before resume, even when the system suspends to disk. + +Q: What do I need to do for ACPI vs. APM vs. etc? + +Drivers need not be aware of the specific power management +technology that is active. They just need to be aware +of when the overlying power management system requests +that they suspend or resume. + +Q: What about device dependencies? + +When a driver registers a device, the power management +subsystem uses the information provided to build a +tree of device dependencies (eg. USB device X is on +USB controller Y which is on PCI bus Z) When power +management wants to suspend a device, it first sends +a suspend request to its driver, then the bus driver, +and so on up to the system bus. Device resumes +proceed in the opposite direction. + +Q: Who do I contact for additional information about + enabling power management for my specific driver/device? + +ACPI4Linux mailing list: acpi@phobos.fs.tum.de +Linux ACPI maintainer: andy_henroid@yahoo.com + +System Interface +---------------- +If you are providing new power management support to Linux (ie. +adding support for something like APM or ACPI), you should +communicate with drivers through the existing generic power +management interface. + +/* + * Send a request to a single device + * + * Parameters: + * dev - PM device previously returned from pm_register or pm_find + * rqst - request type + * data - data, if any, associated with the request + * + * Returns: 0 if the request is successful + * See "pm_callback" return for errors + * + * Details: Forward request to device callback and, if a suspend + * or resume request, update the pm_dev "state" field + * appropriately + */ +int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data); + +/* + * Send a request to all devices + * + * Parameters: + * rqst - request type + * data - data, if any, associated with the request + * + * Returns: 0 if the request is successful + * See "pm_callback" return for errors + * + * Details: Walk list of registered devices and call pm_send + * for each until complete or an error is encountered. + * If an error is encountered for a suspend request, + * return all devices to the state they were in before + * the suspend request. + */ +int pm_send_all(pm_request_t rqst, void *data); + +/* + * Find a matching device + * + * Parameters: + * type - device type (PCI device, system device, or 0 to match all devices) + * from - previous match or NULL to start from the beginning + * + * Returns: Matching device or NULL if none found + */ +struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from); diff -u --recursive --new-file v2.3.47/linux/Documentation/vm/balance linux/Documentation/vm/balance --- v2.3.47/linux/Documentation/vm/balance Fri Jan 28 15:09:06 2000 +++ linux/Documentation/vm/balance Sat Feb 26 20:50:34 2000 @@ -68,11 +68,23 @@ probably because all allocation requests are coming from intr context and all process contexts are sleeping. For 2.3, kswapd does not really need to balance the highmem zone, since intr context does not request -highmem pages. A zone aware kswapd still needs to be implemented. +highmem pages. kswapd looks at the zone_wake_kswapd field in the zone +structure to decide whether a zone needs balancing. Page stealing from process memory and shm is done if stealing the page would alleviate memory pressure on any zone in the page's node that has fallen below its watermark. + +pages_min/pages_low/pages_high/low_on_memory/zone_wake_kswapd: These are +per-zone fields, used to determine when a zone needs to be balanced. When +the number of pages falls below pages_min, the hysteric field low_on_memory +gets set. This stays set till the number of free pages becomes pages_high. +When low_on_memory is set, page allocation requests will try to free some +pages in the zone (providing GFP_WAIT is set in the request). Orthogonal +to this, is the decision to poke kswapd to free some zone pages. That +decision is not hysteresis based, and is done when the number of free +pages is below pages_low; in which case zone_wake_kswapd is also set. + (Good) Ideas that I have heard: 1. Dynamic experience should influence balancing: number of failed requests diff -u --recursive --new-file v2.3.47/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.47/linux/MAINTAINERS Sun Feb 20 21:12:38 2000 +++ linux/MAINTAINERS Fri Feb 25 15:16:37 2000 @@ -726,6 +726,12 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +NVIDIA (RIVA) FRAMEBUFFER DRIVER +P: Jeff Garzik +M: jgarzik@mandrakesoft.com +L: linux-nvidia@lists.surfsouth.com +S: Maintained + OLYMPIC NETWORK DRIVER P: Peter De Shrijver M: p2@ace.ulyssis.sutdent.kuleuven.ac.be @@ -778,7 +784,7 @@ P: Martin Mares M: mj@suse.cz L: linux-kernel@vger.rutgers.edu -S: Maintained +S: Supported PCMCIA SUBSYSTEM P: David Hinds @@ -986,7 +992,7 @@ SVGA HANDLING P: Martin Mares -M: mj@atrey.karlin.mff.cuni.cz +M: mj@suse.cz L: linux-video@atrey.karlin.mff.cuni.cz S: Maintained @@ -1021,6 +1027,12 @@ W: http://www.auk.cx/tms380tr/ S: Maintained +TULIP NETWORK DRIVER +P: Jeff Garzik +M: jgarzik@mandrakesoft.com +L: linux-tulip@cesdis.gsfc.nasa.gov +S: Maintained + U14-34F SCSI DRIVER P: Dario Ballabio M: dario@milano.europe.dg.com @@ -1112,6 +1124,7 @@ VIA 82Cxxx AUDIO DRIVER P: Jeff Garzik M: jgarzik@mandrakesoft.com +L: linux-via@gtf.org S: Maintained VIDEO FOR LINUX diff -u --recursive --new-file v2.3.47/linux/Makefile linux/Makefile --- v2.3.47/linux/Makefile Sun Feb 20 21:12:38 2000 +++ linux/Makefile Fri Feb 25 10:26:42 2000 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 47 +SUBLEVEL = 48 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -27,6 +27,7 @@ AR =$(CROSS_COMPILE)ar NM =$(CROSS_COMPILE)nm STRIP =$(CROSS_COMPILE)strip +OBJCOPY =$(CROSS_COMPILE)objcopy OBJDUMP =$(CROSS_COMPILE)objdump MAKE =make GENKSYMS=/sbin/genksyms @@ -95,9 +96,6 @@ CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer AFLAGS := $(CPPFLAGS) -# use '-fno-strict-aliasing', but only if the compiler can take it -CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi) - # # if you want the RAM disk device, define this to be the # size in blocks. @@ -214,7 +212,7 @@ DRIVERS := $(DRIVERS) drivers/pnp/pnp.o endif -ifdef CONFIG_SGI +ifdef CONFIG_SGI_IP22 DRIVERS := $(DRIVERS) drivers/sgi/sgi.a endif @@ -256,6 +254,9 @@ include arch/$(ARCH)/Makefile +# use '-fno-strict-aliasing', but only if the compiler can take it +CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi) + .S.s: $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -E -o $*.s $< .S.o: @@ -363,7 +364,7 @@ find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print | xargs ctags $$CTAGSF -a && \ find $(SUBDIRS) init -name '*.c' | xargs ctags $$CTAGSF -a -MODFLAGS = -DMODULE +MODFLAGS += -DMODULE ifdef CONFIG_MODULES ifdef CONFIG_MODVERSIONS MODFLAGS += -DMODVERSIONS -include $(HPATH)/linux/modversions.h diff -u --recursive --new-file v2.3.47/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.3.47/linux/arch/alpha/config.in Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/config.in Mon Feb 21 17:38:03 2000 @@ -60,6 +60,7 @@ unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA unset CONFIG_ALPHA_IRONGATE +unset CONFIG_ALPHA_BROKEN_IRQ_MASK # Most of these machines have ISA slots; not exactly sure which don't, # and this doesn't activate hordes of code, so do it always. @@ -177,6 +178,10 @@ if [ "$CONFIG_ALPHA_XL" = "y" ] then define_bool CONFIG_ALPHA_AVANTI y +fi +if [ "$CONFIG_ALPHA_GENERIC" = "y" -o "$CONFIG_ALPHA_PC164" = "y" ] +then + define_bool CONFIG_ALPHA_BROKEN_IRQ_MASK y fi if [ "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \ diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.3.47/linux/arch/alpha/kernel/alpha_ksyms.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/alpha_ksyms.c Mon Feb 21 17:38:03 2000 @@ -98,6 +98,8 @@ EXPORT_SYMBOL(__memsetw); EXPORT_SYMBOL(__constant_c_memset); +EXPORT_SYMBOL(__direct_map_base); +EXPORT_SYMBOL(__direct_map_size); EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); @@ -142,6 +144,10 @@ extern long (*alpha_fp_emul) (unsigned long pc); EXPORT_SYMBOL(alpha_fp_emul_imprecise); EXPORT_SYMBOL(alpha_fp_emul); +#endif + +#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK +EXPORT_SYMBOL(__min_ipl); #endif /* diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.3.47/linux/arch/alpha/kernel/core_tsunami.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/core_tsunami.c Thu Feb 24 22:44:17 2000 @@ -24,7 +24,6 @@ #include "proto.h" #include "pci_impl.h" -int TSUNAMI_bootcpu; static struct { @@ -210,17 +209,23 @@ tsunami_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) { tsunami_pchip *pchip = hose->index ? TSUNAMI_pchip1 : TSUNAMI_pchip0; - - wmb(); + volatile unsigned long *csr; + unsigned long value; /* We can invalidate up to 8 tlb entries in a go. The flush matches against <31:16> in the pci address. */ + csr = &pchip->tlbia.csr; if (((start ^ end) & 0xffff0000) == 0) - pchip->tlbiv.csr = (start & 0xffff0000) >> 12; - else - pchip->tlbia.csr = 0; + csr = &pchip->tlbiv.csr; + /* For TBIA, it doesn't matter what value we write. For TBI, + it's the shifted tag bits. */ + value = (start & 0xffff0000) >> 12; + + wmb(); + *csr = value; mb(); + *csr; } #ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI @@ -229,7 +234,7 @@ { long dont_care, probe_result; int cpu = smp_processor_id(); - int s = swpipl(6); /* Block everything but machine checks. */ + int s = swpipl(IPL_MCHECK - 1); mcheck_taken(cpu) = 0; mcheck_expected(cpu) = 1; @@ -338,9 +343,13 @@ * because of an idiot-syncrasy of the CYPRESS chip. It may * respond to a PCI bus address in the last 1MB of the 4GB * address range. + * + * Note that the TLB lookup logic uses bitwise concatenation, + * not addition, so the required arena alignment is based on + * the size of the window. */ - hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, PAGE_SIZE); - hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, PAGE_SIZE); + hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, 0x00800000>>10); + hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, 0x08000000>>10); __direct_map_base = 0x40000000; __direct_map_size = 0x80000000; @@ -399,8 +408,6 @@ printk("%s: CSR_STR 0x%lx\n", FN, TSUNAMI_dchip->str.csr); printk("%s: CSR_DREV 0x%lx\n", FN, TSUNAMI_dchip->drev.csr); #endif - TSUNAMI_bootcpu = __hard_smp_processor_id(); - /* With multiple PCI busses, we play with I/O as physical addrs. */ ioport_resource.end = ~0UL; iomem_resource.end = ~0UL; @@ -444,12 +451,10 @@ static inline void tsunami_pci_clr_err_1(tsunami_pchip *pchip) { - unsigned int jd; - - jd = pchip->perror.csr; + pchip->perror.csr; pchip->perror.csr = 0x040; mb(); - jd = pchip->perror.csr; + pchip->perror.csr; } static inline void diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.3.47/linux/arch/alpha/kernel/irq.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/irq.c Thu Feb 24 22:44:17 2000 @@ -48,6 +48,12 @@ #define ACTUAL_NR_IRQS NR_IRQS #endif +/* Hack minimum IPL during interupt processing for broken hardware. */ + +#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK +int __min_ipl; +#endif + /* * Performance counter hook. A module can override this to * do something useful. @@ -283,30 +289,32 @@ struct irqaction *action) { int status, cpu = smp_processor_id(); - unsigned long ipl; + int old_ipl, ipl; kstat.irqs[cpu][irq]++; irq_enter(cpu, irq); status = 1; /* Force the "do bottom halves" bit */ - ipl = rdps() & 7; + old_ipl = ipl = getipl(); do { - unsigned long newipl = (action->flags & SA_INTERRUPT ? 7 : 0); - if (newipl != ipl) { - swpipl(newipl); - ipl = newipl; + int new_ipl = IPL_MIN; + if (action->flags & SA_INTERRUPT) + new_ipl = IPL_MAX; + if (new_ipl != ipl) { + setipl(new_ipl); + ipl = new_ipl; } status |= action->flags; action->handler(irq, action->dev_id, regs); action = action->next; } while (action); + if (ipl != old_ipl) + setipl(old_ipl); + if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - if (ipl == 0) - __cli(); - irq_exit(cpu, irq); return status; @@ -325,7 +333,7 @@ spin_lock_irqsave(&irq_controller_lock, flags); if (!irq_desc[irq].depth++) { - irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].status |= IRQ_DISABLED | IRQ_MASKED; irq_desc[irq].handler->disable(irq); } spin_unlock_irqrestore(&irq_controller_lock, flags); @@ -356,14 +364,15 @@ switch (irq_desc[irq].depth) { case 1: { - unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED; - irq_desc[irq].status = status; - if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - irq_desc[irq].status = status | IRQ_REPLAY; + unsigned int status = irq_desc[irq].status; + status &= ~(IRQ_DISABLED | IRQ_MASKED); + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + status |= IRQ_REPLAY; /* ??? We can't re-send on (most?) alpha hw. hw_resend_irq(irq_desc[irq].handler,irq); */ } + irq_desc[irq].status = status; irq_desc[irq].handler->enable(irq); /* fall-through */ } @@ -425,7 +434,7 @@ if (!shared) { irq_desc[irq].depth = 0; - irq_desc[irq].status &= ~IRQ_DISABLED; + irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_MASKED); irq_desc[irq].handler->startup(irq); } spin_unlock_irqrestore(&irq_controller_lock,flags); @@ -500,7 +509,7 @@ /* Found - now remove it from the list of entries. */ *pp = action->next; if (!irq_desc[irq].action) { - irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].status |= IRQ_DISABLED|IRQ_MASKED; irq_desc[irq].handler->shutdown(irq); } spin_unlock_irqrestore(&irq_controller_lock,flags); @@ -669,7 +678,7 @@ * Maximize ipl. If ipl was previously 0 and if this thread * is not in an irq, then take global_irq_lock. */ - if (swpipl(7) == 0 && !local_irq_count(cpu)) + if (swpipl(IPL_MAX) == IPL_MIN && !local_irq_count(cpu)) get_irqlock(cpu, where); } @@ -841,13 +850,25 @@ desc = irq_desc + irq; spin_lock_irq(&irq_controller_lock); /* mask also the RTC */ desc->handler->ack(irq); + status = desc->status; + +#ifndef CONFIG_SMP + /* Look for broken irq masking. */ + if (status & IRQ_MASKED) { + static unsigned long last_printed; + if (time_after(jiffies, last_printed+HZ)) { + printk(KERN_CRIT "Mask didn't work for irq %d!\n", irq); + last_printed = jiffies; + } + } +#endif /* * REPLAY is when Linux resends an IRQ that was dropped earlier. * WAITING is used by probe to mark irqs that are being tested. */ - status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); - status |= IRQ_PENDING; /* we _want_ to handle it */ + status &= ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING | IRQ_MASKED; /* we _want_ to handle it */ /* * If the IRQ is disabled for whatever reason, we cannot @@ -890,9 +911,12 @@ desc->status &= ~IRQ_PENDING; spin_unlock(&irq_controller_lock); } - desc->status &= ~IRQ_INPROGRESS; - if (!(desc->status & IRQ_DISABLED)) + status = desc->status & ~IRQ_INPROGRESS; + if (!(status & IRQ_DISABLED)) { + status &= ~IRQ_MASKED; desc->handler->end(irq); + } + desc->status = status; spin_unlock(&irq_controller_lock); } @@ -1056,7 +1080,7 @@ #ifdef CONFIG_SMP cpu_data[smp_processor_id()].smp_local_irq_count++; smp_percpu_timer_interrupt(®s); - if (smp_processor_id() == smp_boot_cpuid) + if (smp_processor_id() == boot_cpuid) #endif handle_irq(RTC_IRQ, ®s); return; diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c --- v2.3.47/linux/arch/alpha/kernel/pci_iommu.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/pci_iommu.c Thu Feb 24 22:45:28 2000 @@ -133,6 +133,9 @@ unsigned long paddr; dma_addr_t ret; + if (direction == PCI_DMA_NONE) + BUG(); + paddr = virt_to_phys(cpu_addr); /* First check to see if we can use the direct map window. */ @@ -186,12 +189,15 @@ wrote there. */ void -pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, int direction) +pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, + int direction) { struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose; struct pci_iommu_arena *arena; long dma_ofs, npages; + if (direction == PCI_DMA_NONE) + BUG(); if (dma_addr >= __direct_map_base && dma_addr < __direct_map_base + __direct_map_size) { @@ -247,7 +253,8 @@ } memset(cpu_addr, 0, size); - *dma_addrp = pci_map_single(pdev, cpu_addr, size, PCI_DMA_BIDIRECTIONAL); + *dma_addrp = pci_map_single(pdev, cpu_addr, size, + PCI_DMA_BIDIRECTIONAL); if (*dma_addrp == 0) { free_pages((unsigned long)cpu_addr, order); return NULL; @@ -424,13 +431,17 @@ } int -pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) +pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, + int direction) { struct scatterlist *start, *end, *out; struct pci_controler *hose; struct pci_iommu_arena *arena; dma_addr_t max_dma; + if (direction == PCI_DMA_NONE) + BUG(); + /* Fast path single entry scatterlists. */ if (nents == 1) { sg->dma_length = sg->length; @@ -499,7 +510,8 @@ above. */ void -pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) +pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, + int direction) { struct pci_controler *hose; struct pci_iommu_arena *arena; @@ -507,6 +519,9 @@ dma_addr_t max_dma; dma_addr_t fstart, fend; + if (direction == PCI_DMA_NONE) + BUG(); + if (! alpha_mv.mv_pci_tbi) return; @@ -554,4 +569,34 @@ alpha_mv.mv_pci_tbi(hose, fstart, fend); DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg)); +} + +/* Return whether the given PCI device DMA address mask can be + supported properly. */ + +int +pci_dma_supported(struct pci_dev *pdev, dma_addr_t mask) +{ + struct pci_controler *hose; + struct pci_iommu_arena *arena; + + /* If there exists a direct map, and the mask fits either + MAX_DMA_ADDRESS defined such that GFP_DMA does something + useful, or the total system memory as shifted by the + map base. */ + if (__direct_map_size != 0 + && (__direct_map_base + MAX_DMA_ADDRESS-IDENT_ADDR-1 <= mask + || __direct_map_base + (max_low_pfn<sysdata : pci_isa_hose; + arena = hose->sg_isa; + if (arena && arena->dma_base + arena->size <= mask) + return 1; + arena = hose->sg_pci; + if (arena && arena->dma_base + arena->size <= mask) + return 1; + + return 0; } diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.3.47/linux/arch/alpha/kernel/process.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/process.c Thu Feb 24 22:43:39 2000 @@ -90,55 +90,82 @@ } } + +struct halt_info { + int mode; + char *restart_cmd; +}; + static void -common_shutdown(int mode, char *restart_cmd) +common_shutdown_1(void *generic_ptr) { - /* The following currently only has any effect on SRM. We should - fix MILO to understand it. Should be pretty easy. Also we can - support RESTART2 via the ipc_buffer machinations pictured below, - which SRM ignores. */ + struct halt_info *how = (struct halt_info *)generic_ptr; + struct percpu_struct *cpup; + unsigned long *pflags, flags; + int cpuid = smp_processor_id(); + + /* No point in taking interrupts anymore. */ + __cli(); + + cpup = (struct percpu_struct *) + ((unsigned long)hwrpb + hwrpb->processor_offset + + hwrpb->processor_size * cpuid); + pflags = &cpup->flags; + flags = *pflags; + + /* Clear reason to "default"; clear "bootstrap in progress". */ + flags &= ~0x00ff0001UL; + +#ifdef __SMP__ + /* Secondaries halt here. */ + if (cpuid != boot_cpuid) { + flags |= 0x00040000UL; /* "remain halted" */ + *pflags = flags; + clear_bit(cpuid, &cpu_present_mask); + halt(); + } +#endif - if (alpha_using_srm) { - struct percpu_struct *cpup; - unsigned long flags; - - cpup = (struct percpu_struct *) - ((unsigned long)hwrpb + hwrpb->processor_offset); - - flags = cpup->flags; - - /* Clear reason to "default"; clear "bootstrap in progress". */ - flags &= ~0x00ff0001UL; - - if (mode == LINUX_REBOOT_CMD_RESTART) { - if (!restart_cmd) { - flags |= 0x00020000UL; /* "cold bootstrap" */ - cpup->ipc_buffer[0] = 0; - } else { - flags |= 0x00030000UL; /* "warm bootstrap" */ - strncpy((char *)cpup->ipc_buffer, restart_cmd, - sizeof(cpup->ipc_buffer)); - } + if (how->mode == LINUX_REBOOT_CMD_RESTART) { + if (!how->restart_cmd) { + flags |= 0x00020000UL; /* "cold bootstrap" */ } else { - flags |= 0x00040000UL; /* "remain halted" */ + /* For SRM, we could probably set environment + variables to get this to work. We'd have to + delay this until after srm_paging_stop unless + we ever got srm_fixup working. + + At the moment, SRM will use the last boot device, + but the file and flags will be the defaults, when + doing a "warm" bootstrap. */ + flags |= 0x00030000UL; /* "warm bootstrap" */ } - - cpup->flags = flags; - mb(); + } else { + flags |= 0x00040000UL; /* "remain halted" */ + } + *pflags = flags; - /* reset_for_srm(); */ - set_hae(srm_hae); +#ifdef __SMP__ + /* Wait for the secondaries to halt. */ + clear_bit(boot_cpuid, &cpu_present_mask); + while (cpu_present_mask) + barrier(); +#endif + /* If booted from SRM, reset some of the original environment. */ + if (alpha_using_srm) { #ifdef CONFIG_DUMMY_CONSOLE - /* This has the effect of reseting the VGA video origin. */ + /* This has the effect of resetting the VGA video origin. */ take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1); #endif + /* reset_for_srm(); */ + set_hae(srm_hae); } if (alpha_mv.kill_arch) - alpha_mv.kill_arch(mode); + alpha_mv.kill_arch(how->mode); - if (!alpha_using_srm && mode != LINUX_REBOOT_CMD_RESTART) { + if (! alpha_using_srm && how->mode != LINUX_REBOOT_CMD_RESTART) { /* Unfortunately, since MILO doesn't currently understand the hwrpb bits above, we can't reliably halt the processor and keep it halted. So just loop. */ @@ -149,6 +176,18 @@ srm_paging_stop(); halt(); +} + +static void +common_shutdown(int mode, char *restart_cmd) +{ + struct halt_info args; + args.mode = mode; + args.restart_cmd = restart_cmd; +#ifdef __SMP__ + smp_call_function(common_shutdown_1, &args, 1, 0); +#endif + common_shutdown_1(&args); } void diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h --- v2.3.47/linux/arch/alpha/kernel/proto.h Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/proto.h Thu Feb 24 22:43:39 2000 @@ -74,13 +74,14 @@ /* setup.c */ extern unsigned long srm_hae; +extern int boot_cpuid; /* smp.c */ extern void setup_smp(void); extern int smp_info(char *buffer); extern void handle_ipi(struct pt_regs *); extern void smp_percpu_timer_interrupt(struct pt_regs *); -extern int smp_boot_cpuid; +extern unsigned long cpu_present_mask; /* bios32.c */ /* extern void reset_for_srm(void); */ diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/semaphore.c linux/arch/alpha/kernel/semaphore.c --- v2.3.47/linux/arch/alpha/kernel/semaphore.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/semaphore.c Thu Feb 24 22:36:04 2000 @@ -173,7 +173,7 @@ " subl %0,1,%0\n" " stl_c %2,%1\n" " bne %2,2f\n" - ".section .text2,\"ax\"\n" + ".subsection 2\n" "2: br 1b\n" ".previous" : "=r"(count), "=m"(sem->count), "=r"(tmp) @@ -226,7 +226,7 @@ " ldah %0,%3(%0)\n" " stl_c %2,%1\n" " bne %2,2f\n" - ".section .text2,\"ax\"\n" + ".subsection 2\n" "2: br 1b\n" ".previous" : "=r"(count), "=m"(sem->count), "=r"(tmp) diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.3.47/linux/arch/alpha/kernel/setup.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/setup.c Thu Feb 24 22:43:39 2000 @@ -50,6 +50,9 @@ struct hwrpb_struct *hwrpb; unsigned long srm_hae; +/* Which processor we booted from. */ +int boot_cpuid; + #ifdef CONFIG_ALPHA_GENERIC struct alpha_machine_vector alpha_mv; int alpha_using_srm; @@ -351,6 +354,7 @@ char *type_name, *var_name, *p; hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr); + boot_cpuid = hard_smp_processor_id(); /* * Locate the command line. diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.3.47/linux/arch/alpha/kernel/smp.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/smp.c Thu Feb 24 22:43:39 2000 @@ -62,11 +62,13 @@ /* Set to a secondary's cpuid when it comes online. */ static unsigned long smp_secondary_alive; -unsigned long cpu_present_mask; /* Which cpus ids came online. */ -static unsigned long __cpu_present_mask __initdata = 0; /* cpu reported in the hwrpb */ +/* Which cpus ids came online. */ +unsigned long cpu_present_mask; + +/* cpus reported in the hwrpb */ +static unsigned long hwrpb_cpu_present_mask __initdata = 0; static int max_cpus = -1; /* Command-line limitation. */ -int smp_boot_cpuid; /* Which processor we booted from. */ int smp_num_probed; /* Internal processor count */ int smp_num_cpus = 1; /* Number that came online. */ int smp_threads_ready; /* True once the per process idle is forked. */ @@ -486,10 +488,9 @@ struct percpu_struct *cpubase, *cpu; int i; - smp_boot_cpuid = hard_smp_processor_id(); - if (smp_boot_cpuid != 0) { + if (boot_cpuid != 0) { printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n", - smp_boot_cpuid); + boot_cpuid); } if (hwrpb->nr_processors > 1) { @@ -508,7 +509,7 @@ if ((cpu->flags & 0x1cc) == 0x1cc) { smp_num_probed++; /* Assume here that "whami" == index */ - __cpu_present_mask |= (1L << i); + hwrpb_cpu_present_mask |= (1L << i); cpu->pal_revision = boot_cpu_palrev; } @@ -519,12 +520,12 @@ } } else { smp_num_probed = 1; - __cpu_present_mask = (1L << smp_boot_cpuid); + hwrpb_cpu_present_mask = (1L << boot_cpuid); } - cpu_present_mask = 1L << smp_boot_cpuid; + cpu_present_mask = 1L << boot_cpuid; printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n", - smp_num_probed, __cpu_present_mask); + smp_num_probed, hwrpb_cpu_present_mask); } /* @@ -541,13 +542,13 @@ memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map)); memset(ipi_data, 0, sizeof(ipi_data)); - __cpu_number_map[smp_boot_cpuid] = 0; - __cpu_logical_map[0] = smp_boot_cpuid; - current->processor = smp_boot_cpuid; + __cpu_number_map[boot_cpuid] = 0; + __cpu_logical_map[0] = boot_cpuid; + current->processor = boot_cpuid; - smp_store_cpu_info(smp_boot_cpuid); + smp_store_cpu_info(boot_cpuid); smp_tune_scheduling(); - smp_setup_percpu_timer(smp_boot_cpuid); + smp_setup_percpu_timer(boot_cpuid); init_idle(); @@ -565,10 +566,10 @@ cpu_count = 1; for (i = 0; i < NR_CPUS; i++) { - if (i == smp_boot_cpuid) + if (i == boot_cpuid) continue; - if (((__cpu_present_mask >> i) & 1) == 0) + if (((hwrpb_cpu_present_mask >> i) & 1) == 0) continue; if (smp_boot_one_cpu(i, cpu_count)) @@ -1023,7 +1024,7 @@ " stl_c %0,%1\n" " beq %0,3f\n" "4: mb\n" - ".section .text2,\"ax\"\n" + ".subsection 2\n" "2: ldl %0,%1\n" " subq %2,1,%2\n" "3: blt %2,4b\n" @@ -1097,7 +1098,7 @@ " stl_c %1,%0\n" " beq %1,6f\n" "4: mb\n" - ".section .text2,\"ax\"\n" + ".subsection 2\n" "6: blt %3,4b # debug\n" " subl %3,1,%3 # debug\n" " ldl %1,%0\n" @@ -1140,7 +1141,7 @@ " stl_c %1,%0;" " beq %1,6f;" "4: mb\n" - ".section .text2,\"ax\"\n" + ".subsection 2\n" "6: ldl %1,%0;" " blt %2,4b # debug\n" " subl %2,1,%2 # debug\n" diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/sys_cabriolet.c linux/arch/alpha/kernel/sys_cabriolet.c --- v2.3.47/linux/arch/alpha/kernel/sys_cabriolet.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/sys_cabriolet.c Mon Feb 21 17:38:03 2000 @@ -126,6 +126,30 @@ setup_irq(16+4, &isa_cascade_irqaction); } +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164) +static void +pc164_device_interrupt(unsigned long v, struct pt_regs *r) +{ + /* In theory, the PC164 has the same interrupt hardware as + the other Cabriolet based systems. However, something + got screwed up late in the development cycle which broke + the interrupt masking hardware. Repeat, it is not + possible to mask and ack interrupts. At all. + + In an attempt to work around this, while processing + interrupts, we do not allow the IPL to drop below what + it is currently. This prevents the possibility of + recursion. + + ??? Another option might be to force all PCI devices + to use edge triggered rather than level triggered + interrupts. That might be too invasive though. */ + + __min_ipl = getipl(); + cabriolet_device_interrupt(v, r); + __min_ipl = 0; +} +#endif /* * The EB66+ is very similar to the EB66 except that it does not have @@ -379,7 +403,7 @@ min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 35, - device_interrupt: cabriolet_device_interrupt, + device_interrupt: pc164_device_interrupt, init_arch: cia_init_arch, init_irq: cabriolet_init_irq, diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c --- v2.3.47/linux/arch/alpha/kernel/sys_dp264.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/sys_dp264.c Thu Feb 24 22:44:17 2000 @@ -33,94 +33,80 @@ #include "machvec_impl.h" +/* Note mask bit is true for ENABLED irqs. */ static unsigned long cached_irq_mask; - -#define TSUNAMI_SET_IRQ_MASK(cpu, value) \ -do { \ - volatile unsigned long *csr; \ - csr = &TSUNAMI_cchip->dim##cpu##.csr; \ - *csr = (value); \ - mb(); \ - *csr; \ -} while(0) - -static inline void -do_flush_irq_mask(unsigned long value) -{ - switch (TSUNAMI_bootcpu) { - case 0: - TSUNAMI_SET_IRQ_MASK(0, value); - break; - case 1: - TSUNAMI_SET_IRQ_MASK(1, value); - break; - case 2: - TSUNAMI_SET_IRQ_MASK(2, value); - break; - case 3: - TSUNAMI_SET_IRQ_MASK(3, value); - break; - } -} - -#ifdef CONFIG_SMP -static inline void -do_flush_smp_irq_mask(unsigned long value) -{ - extern unsigned long cpu_present_mask; - unsigned long other_cpus = cpu_present_mask & ~(1L << TSUNAMI_bootcpu); - - if (other_cpus & 1) - TSUNAMI_SET_IRQ_MASK(0, value); - if (other_cpus & 2) - TSUNAMI_SET_IRQ_MASK(1, value); - if (other_cpus & 4) - TSUNAMI_SET_IRQ_MASK(2, value); - if (other_cpus & 8) - TSUNAMI_SET_IRQ_MASK(3, value); -} -#endif - static void -dp264_flush_irq_mask(unsigned long mask) +tsunami_update_irq_hw(unsigned long mask, unsigned long isa_enable) { - unsigned long value; + register tsunami_cchip *cchip = TSUNAMI_cchip; + register int bcpu = boot_cpuid; #ifdef CONFIG_SMP - do_flush_smp_irq_mask(mask); + register unsigned long cpm = cpu_present_mask; + volatile unsigned long *dim0, *dim1, *dim2, *dim3; + unsigned long mask0, mask1, mask2, mask3, maskB, dummy; + + mask0 = mask1 = mask2 = mask3 = mask; + maskB = mask | isa_enable; + if (bcpu == 0) mask0 = maskB; + if (bcpu == 1) mask1 = maskB; + if (bcpu == 2) mask2 = maskB; + if (bcpu == 3) mask3 = maskB; + + dim0 = &cchip->dim0.csr; + dim1 = &cchip->dim1.csr; + dim2 = &cchip->dim2.csr; + dim3 = &cchip->dim3.csr; + if ((cpm & 1) == 0) dim0 = &dummy; + if ((cpm & 2) == 0) dim1 = &dummy; + if ((cpm & 4) == 0) dim2 = &dummy; + if ((cpm & 8) == 0) dim3 = &dummy; + + *dim0 = mask0; + *dim1 = mask1; + *dim2 = mask2; + *dim3 = mask3; + mb(); + *dim0; + *dim1; + *dim2; + *dim3; +#else + volatile unsigned long *dimB = &cchip->dim1.csr; + if (bcpu == 0) dimB = &cchip->dim0.csr; + if (bcpu == 2) dimB = &cchip->dim2.csr; + if (bcpu == 3) dimB = &cchip->dim3.csr; + *dimB = mask | isa_enable; + mb(); + *dimB; #endif - - value = mask | (1UL << 55) | 0xffff; /* isa irqs always enabled */ - do_flush_irq_mask(value); } -static void -clipper_flush_irq_mask(unsigned long mask) +static inline void +dp264_update_irq_hw(unsigned long mask) { - unsigned long value; - - value = mask >> 16; -#ifdef CONFIG_SMP - do_flush_smp_irq_mask(value); -#endif + tsunami_update_irq_hw(mask, (1UL << 55) | 0xffff); +} - value = value | (1UL << 55); /* master ISA enable */ - do_flush_irq_mask(value); +static inline void +clipper_update_irq_hw(unsigned long mask) +{ + tsunami_update_irq_hw(mask, 1UL << 55); } static inline void dp264_enable_irq(unsigned int irq) { cached_irq_mask |= 1UL << irq; - dp264_flush_irq_mask(cached_irq_mask); + dp264_update_irq_hw(cached_irq_mask); } static void dp264_disable_irq(unsigned int irq) { cached_irq_mask &= ~(1UL << irq); - dp264_flush_irq_mask(cached_irq_mask); + dp264_update_irq_hw(cached_irq_mask); } static unsigned int @@ -134,14 +120,14 @@ clipper_enable_irq(unsigned int irq) { cached_irq_mask |= 1UL << irq; - clipper_flush_irq_mask(cached_irq_mask); + clipper_update_irq_hw(cached_irq_mask); } static void clipper_disable_irq(unsigned int irq) { cached_irq_mask &= ~(1UL << irq); - clipper_flush_irq_mask(cached_irq_mask); + clipper_update_irq_hw(cached_irq_mask); } static unsigned int @@ -271,7 +257,7 @@ if (alpha_using_srm) alpha_mv.device_interrupt = dp264_srm_device_interrupt; - dp264_flush_irq_mask(0UL); + dp264_update_irq_hw(0UL); init_i8259a_irqs(); init_rtc_irq(); @@ -289,7 +275,7 @@ if (alpha_using_srm) alpha_mv.device_interrupt = clipper_srm_device_interrupt; - clipper_flush_irq_mask(0UL); + clipper_update_irq_hw(0UL); init_i8259a_irqs(); init_rtc_irq(); diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/sys_sio.c linux/arch/alpha/kernel/sys_sio.c --- v2.3.47/linux/arch/alpha/kernel/sys_sio.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/sys_sio.c Thu Feb 24 22:45:57 2000 @@ -391,7 +391,7 @@ nr_irqs: 16, device_interrupt: isa_device_interrupt, - init_arch: lca_init_arch, + init_arch: apecs_init_arch, init_irq: sio_init_irq, init_rtc: common_init_rtc, init_pci: noname_init_pci, diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.3.47/linux/arch/alpha/kernel/time.c Sun Feb 20 21:12:38 2000 +++ linux/arch/alpha/kernel/time.c Mon Feb 21 10:56:40 2000 @@ -22,7 +22,6 @@ * fixed algorithm in do_gettimeofday() for calculating the precise time * from processor cycle counter (now taking lost_ticks into account) */ -#include #include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.3.47/linux/arch/alpha/kernel/traps.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/traps.c Mon Feb 21 17:35:40 2000 @@ -215,8 +215,10 @@ /* EV4 does not implement anything except normal rounding. Everything else will come here as an illegal instruction. Emulate them. */ - if (alpha_fp_emul(regs.pc - 4)) + if (alpha_fp_emul(regs.pc)) { + regs.pc += 4; return; + } } send_sig(SIGILL, current, 1); break; diff -u --recursive --new-file v2.3.47/linux/arch/alpha/vmlinux.lds linux/arch/alpha/vmlinux.lds --- v2.3.47/linux/arch/alpha/vmlinux.lds Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/vmlinux.lds Thu Feb 24 22:36:04 2000 @@ -5,7 +5,6 @@ . = 0xfffffc0000310000; _text = .; .text : { *(.text) } - .text2 : { *(.text2) } _etext = .; /* Exception table */ diff -u --recursive --new-file v2.3.47/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.3.47/linux/arch/arm/kernel/armksyms.c Sun Feb 13 19:29:03 2000 +++ linux/arch/arm/kernel/armksyms.c Thu Feb 24 22:44:47 2000 @@ -165,7 +165,6 @@ EXPORT_SYMBOL_NOVERS(strchr); EXPORT_SYMBOL_NOVERS(strlen); EXPORT_SYMBOL_NOVERS(strnlen); -EXPORT_SYMBOL_NOVERS(strspn); EXPORT_SYMBOL_NOVERS(strpbrk); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strrchr); diff -u --recursive --new-file v2.3.47/linux/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c --- v2.3.47/linux/arch/arm/mm/consistent.c Wed Feb 16 17:03:51 2000 +++ linux/arch/arm/mm/consistent.c Thu Feb 24 22:44:47 2000 @@ -23,7 +23,6 @@ { int order; unsigned long page; - struct vm_struct *area; void *ret; if (in_interrupt()) @@ -40,15 +39,10 @@ *dma_handle = virt_to_bus((void *)page); - area = get_vm_area(size, VM_IOREMAP); /* maybe new type? */ - if (!area) - goto no_area; - ret = __ioremap(virt_to_phys((void *)page), PAGE_SIZE << order, 0); if (ret) return ret; -no_area: free_pages(page, order); no_page: BUG(); diff -u --recursive --new-file v2.3.47/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.47/linux/arch/i386/defconfig Sun Feb 20 21:12:38 2000 +++ linux/arch/i386/defconfig Sat Feb 26 20:45:15 2000 @@ -109,10 +109,12 @@ # CONFIG_BLK_DEV_ISAPNP is not set CONFIG_BLK_DEV_RZ1000=y CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y # CONFIG_BLK_DEV_IDEDMA_PCI is not set # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_AEC6210 is not set # CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_CS5530 is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_BLK_CPQ_DA is not set @@ -393,6 +395,7 @@ # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set +# CONFIG_EFI_RTC is not set # # Video For Linux diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c --- v2.3.47/linux/arch/i386/kernel/acpi.c Wed Feb 16 17:03:51 2000 +++ linux/arch/i386/kernel/acpi.c Thu Feb 24 10:11:24 2000 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -379,13 +380,14 @@ ioremap((unsigned long) addr, table_size); } - if (!table) { - /* ioremap is a pain, it returns NULL if the - * table starts within mapped physical memory. - * Hopefully, no table straddles a mapped/unmapped - * physical memory boundary, ugh + if (!table && addr < virt_to_phys(high_memory)) { + /* sometimes we see ACPI tables in low memory + * and not reserved by the memory map (E820) code, + * who is at fault for this? BIOS? */ - table = (struct acpi_table*) phys_to_virt(addr); + printk(KERN_ERR + "ACPI: unreserved table memory @ 0x%p!\n", + (void*) addr); } } return table; @@ -933,9 +935,9 @@ int status = 0; if (state == ACPI_D0) - status = pm_send_request(PM_RESUME, (void*) state); + status = pm_send_all(PM_RESUME, (void*) state); else - status = pm_send_request(PM_SUSPEND, (void*) state); + status = pm_send_all(PM_SUSPEND, (void*) state); return status; } @@ -1333,10 +1335,7 @@ if (acpi_claim_ioports(acpi_facp)) { printk(KERN_ERR "ACPI: I/O port allocation failed\n"); - if (pci_driver_registered) - pci_unregister_driver(&acpi_driver); - acpi_destroy_tables(); - return -ENODEV; + goto err_out; } if (acpi_facp->sci_int @@ -1347,12 +1346,7 @@ acpi_facp)) { printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", acpi_facp->sci_int); - - if (pci_driver_registered) - pci_unregister_driver(&acpi_driver); - acpi_destroy_tables(); - - return -ENODEV; + goto err_out; } acpi_sysctl = register_sysctl_table(acpi_dir_table, 1); @@ -1379,6 +1373,13 @@ pm_idle = acpi_idle; return 0; + +err_out: + if (pci_driver_registered) + pci_unregister_driver(&acpi_driver); + acpi_destroy_tables(); + + return -ENODEV; } /* diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.3.47/linux/arch/i386/kernel/apm.c Sun Feb 20 21:12:38 2000 +++ linux/arch/i386/kernel/apm.c Thu Feb 24 22:41:16 2000 @@ -333,7 +333,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); static struct apm_user * user_list = NULL; -static char driver_version[] = "1.12"; /* no spaces */ +static char driver_version[] = "1.13"; /* no spaces */ static char * apm_event_name[] = { "system standby", @@ -590,7 +590,11 @@ continue; if (hlt_counter) continue; - asm volatile("sti ; hlt" : : : "memory"); + asm volatile("cli" : : : "memory"); + if (!current->need_resched) + asm volatile("sti ; hlt" : : : "memory"); + else + asm volatile("sti" : : : "memory"); continue; } @@ -635,7 +639,7 @@ */ #ifdef CONFIG_SMP /* Some bioses don't like being called from CPU != 0 */ - while (cpu_number_map[smp_processor_id()] != 0) { + while (cpu_number_map(smp_processor_id()) != 0) { kernel_thread(apm_magic, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); schedule(); @@ -916,7 +920,7 @@ case APM_CRITICAL_SUSPEND: case APM_USER_SUSPEND: /* map all suspends to ACPI D3 */ - if (pm_send_request(PM_SUSPEND, (void *)3)) { + if (pm_send_all(PM_SUSPEND, (void *)3)) { if (apm_bios_info.version > 0x100) apm_set_power_state(APM_STATE_REJECT); return 0; @@ -925,7 +929,7 @@ case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: /* map all resumes to ACPI D0 */ - (void) pm_send_request(PM_RESUME, (void *)0); + (void) pm_send_all(PM_RESUME, (void *)0); break; } diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.3.47/linux/arch/i386/kernel/entry.S Thu Feb 10 17:11:03 2000 +++ linux/arch/i386/kernel/entry.S Mon Feb 21 10:59:36 2000 @@ -181,6 +181,8 @@ call SYMBOL_NAME(schedule_tail) addl $4, %esp GET_CURRENT(%ebx) + testb $0x20,flags(%ebx) # PF_TRACESYS + jne tracesys_exit jmp ret_from_sys_call /* diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.3.47/linux/arch/i386/kernel/i386_ksyms.c Sun Feb 20 21:12:38 2000 +++ linux/arch/i386/kernel/i386_ksyms.c Thu Feb 24 22:41:16 2000 @@ -144,6 +144,4 @@ EXPORT_SYMBOL(get_wchan); - -EXPORT_SYMBOL(local_bh_count); -EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(irq_stat); diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/i8259.c linux/arch/i386/kernel/i8259.c --- v2.3.47/linux/arch/i386/kernel/i8259.c Sat Feb 12 11:22:10 2000 +++ linux/arch/i386/kernel/i8259.c Thu Feb 24 22:41:16 2000 @@ -127,11 +127,14 @@ * moves to arch independent land */ -void enable_8259A_irq(unsigned int irq); -void disable_8259A_irq(unsigned int irq); +static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED; + +static void end_8259A_irq (unsigned int irq) +{ + if (!(irq_desc[irq].status & IRQ_DISABLED)) + enable_8259A_irq(irq); +} -/* shutdown is same as "disable" */ -#define end_8259A_irq enable_8259A_irq #define shutdown_8259A_irq disable_8259A_irq void mask_and_ack_8259A(unsigned int); @@ -149,7 +152,8 @@ enable_8259A_irq, disable_8259A_irq, mask_and_ack_8259A, - end_8259A_irq + end_8259A_irq, + NULL }; /* @@ -183,30 +187,45 @@ void disable_8259A_irq(unsigned int irq) { unsigned int mask = 1 << irq; + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask |= mask; if (irq & 8) outb(cached_A1,0xA1); else outb(cached_21,0x21); + spin_unlock_irqrestore(&i8259A_lock, flags); } void enable_8259A_irq(unsigned int irq) { unsigned int mask = ~(1 << irq); + unsigned long flags; + + spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask &= mask; if (irq & 8) outb(cached_A1,0xA1); else outb(cached_21,0x21); + spin_unlock_irqrestore(&i8259A_lock, flags); } int i8259A_irq_pending(unsigned int irq) { unsigned int mask = 1<> 8)); + ret = inb(0x20) & mask; + else + ret = inb(0xA0) & (mask >> 8); + spin_unlock_irqrestore(&i8259A_lock, flags); + + return ret; } void make_8259A_irq(unsigned int irq) @@ -247,7 +266,9 @@ void mask_and_ack_8259A(unsigned int irq) { unsigned int irqmask = 1 << irq; + unsigned long flags; + spin_lock_irqsave(&i8259A_lock, flags); /* * Lightweight spurious IRQ detection. We do not want * to overdo spurious IRQ handling - it's usually a sign @@ -278,6 +299,7 @@ outb(cached_21,0x21); outb(0x20,0x20); /* 'generic EOI' to master */ } + spin_unlock_irqrestore(&i8259A_lock, flags); return; spurious_8259A_irq: diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.3.47/linux/arch/i386/kernel/io_apic.c Wed Feb 16 17:03:51 2000 +++ linux/arch/i386/kernel/io_apic.c Thu Feb 24 22:41:16 2000 @@ -28,6 +28,8 @@ #include #include +static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED; + /* * # of IO-APICs and # of IRQ routing registers */ @@ -87,9 +89,8 @@ entry->pin = pin; } -#define DO_ACTION(name,R,ACTION, FINAL) \ +#define __DO_ACTION(name,R,ACTION, FINAL) \ \ -static void name##_IO_APIC_irq(unsigned int irq) \ { \ int pin; \ struct irq_pin_list *entry = irq_2_pin + irq; \ @@ -109,8 +110,31 @@ FINAL; \ } -DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */ -DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ +#define DO_ACTION(name,R,ACTION, FINAL) \ + \ +static void name##_IO_APIC_irq(unsigned int irq) \ +__DO_ACTION(name,R,ACTION, FINAL) + +DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */ +DO_ACTION( __unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ + +static void mask_IO_APIC_irq (unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + __mask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} + +static void unmask_IO_APIC_irq (unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + __unmask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); +} void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { @@ -537,7 +561,7 @@ entry.delivery_mode = dest_LowestPrio; entry.dest_mode = 1; /* logical delivery */ entry.mask = 0; /* enable IRQ */ - entry.dest.logical.logical_dest = APIC_ALL_CPUS; /* all CPUs */ + entry.dest.logical.logical_dest = APIC_ALL_CPUS; idx = find_irq_entry(apic,pin,mp_INT); if (idx == -1) { @@ -1026,16 +1050,16 @@ static int __init nmi_irq_works(void) { - atomic_t tmp[NR_CPUS]; + irq_cpustat_t tmp[NR_CPUS]; int j, cpu; - memcpy(tmp, nmi_counter, sizeof(tmp)); + memcpy(tmp, irq_stat, sizeof(tmp)); sti(); mdelay(50); for (j = 0; j < smp_num_cpus; j++) { cpu = cpu_logical_map(j); - if (atomic_read(nmi_counter+cpu) - atomic_read(tmp+cpu) <= 3) { + if (atomic_read(&nmi_counter(cpu)) - atomic_read(&tmp[cpu].__nmi_counter) <= 3) { printk("CPU#%d NMI appears to be stuck.\n", cpu); return 0; } @@ -1055,14 +1079,9 @@ * that was delayed but this is now handled in the device * independent code. */ -static void enable_edge_ioapic_irq(unsigned int irq) -{ - unmask_IO_APIC_irq(irq); -} +#define enable_edge_ioapic_irq unmask_IO_APIC_irq -static void disable_edge_ioapic_irq(unsigned int irq) -{ -} +static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ } /* * Starting up a edge-triggered IO-APIC interrupt is @@ -1077,12 +1096,17 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) { int was_pending = 0; + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); if (irq < 16) { disable_8259A_irq(irq); if (i8259A_irq_pending(irq)) was_pending = 1; } - enable_edge_ioapic_irq(irq); + __unmask_IO_APIC_irq(irq); + spin_unlock_irqrestore(&ioapic_lock, flags); + return was_pending; } @@ -1093,14 +1117,15 @@ * interrupt for real. This prevents IRQ storms from unhandled * devices. */ -void static ack_edge_ioapic_irq(unsigned int irq) +static void ack_edge_ioapic_irq(unsigned int irq) { if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED)) mask_IO_APIC_irq(irq); ack_APIC_irq(); } -void static end_edge_ioapic_irq(unsigned int i){} + +static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ } /* @@ -1108,23 +1133,46 @@ * and shutting down and starting up the interrupt * is the same as enabling and disabling them -- except * with a startup need to return a "was pending" value. + * + * Level triggered interrupts are special because we + * do not touch any IO-APIC register while handling + * them. We ack the APIC in the end-IRQ handler, not + * in the start-IRQ-handler. Protection against reentrance + * from the same interrupt is still provided, both by the + * generic IRQ layer and by the fact that an unacked local + * APIC does not accept IRQs. */ -static unsigned int startup_level_ioapic_irq(unsigned int irq) +static unsigned int startup_level_ioapic_irq (unsigned int irq) { unmask_IO_APIC_irq(irq); + return 0; /* don't check for pending */ } #define shutdown_level_ioapic_irq mask_IO_APIC_irq #define enable_level_ioapic_irq unmask_IO_APIC_irq #define disable_level_ioapic_irq mask_IO_APIC_irq -#define end_level_ioapic_irq unmask_IO_APIC_irq -void static mask_and_ack_level_ioapic_irq(unsigned int i) + +static void end_level_ioapic_irq (unsigned int i) { - mask_IO_APIC_irq(i); ack_APIC_irq(); } +static void mask_and_ack_level_ioapic_irq (unsigned int i) { /* nothing */ } + +static void set_ioapic_affinity (unsigned int irq, unsigned int mask) +{ + unsigned long flags; + /* + * Only the first 8 bits are valid. + */ + mask = mask << 24; + + spin_lock_irqsave(&ioapic_lock, flags); + __DO_ACTION( target, 1, = mask, ) + spin_unlock_irqrestore(&ioapic_lock, flags); +} + /* * Level and edge triggered IO-APIC interrupts need different handling, * so we use two separate IRQ descriptors. Edge triggered IRQs can be @@ -1141,7 +1189,8 @@ enable_edge_ioapic_irq, disable_edge_ioapic_irq, ack_edge_ioapic_irq, - end_edge_ioapic_irq + end_edge_ioapic_irq, + set_ioapic_affinity, }; static struct hw_interrupt_type ioapic_level_irq_type = { @@ -1151,7 +1200,8 @@ enable_level_ioapic_irq, disable_level_ioapic_irq, mask_and_ack_level_ioapic_irq, - end_level_ioapic_irq + end_level_ioapic_irq, + set_ioapic_affinity, }; static inline void init_IO_APIC_traps(void) @@ -1185,12 +1235,12 @@ } } -void static ack_lapic_irq (unsigned int irq) +static void ack_lapic_irq (unsigned int irq) { ack_APIC_irq(); } -void static end_lapic_irq (unsigned int i) { /* nothing */ } +static void end_lapic_irq (unsigned int i) { /* nothing */ } static struct hw_interrupt_type lapic_irq_type = { "local-APIC-edge", diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.3.47/linux/arch/i386/kernel/irq.c Sun Feb 20 21:12:38 2000 +++ linux/arch/i386/kernel/irq.c Thu Feb 24 22:41:16 2000 @@ -31,21 +31,20 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include #include #include -unsigned int local_bh_count[NR_CPUS]; -unsigned int local_irq_count[NR_CPUS]; - -extern atomic_t nmi_counter[NR_CPUS]; /* * Linux has a controller-independent x86 interrupt architecture. @@ -63,17 +62,15 @@ * interrupt controllers, without having to do assembly magic. */ -/* - * Micro-access to controllers is serialized over the whole - * system. We never hold this lock when we call the actual - * IRQ handler. - */ -spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; +irq_cpustat_t irq_stat [NR_CPUS]; + /* * Controller mappings for all interrupt sources: */ irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; + { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; + +static void register_irq_proc (unsigned int irq); /* * Special irq handlers. @@ -164,7 +161,7 @@ p += sprintf(p, "NMI: "); for (j = 0; j < smp_num_cpus; j++) p += sprintf(p, "%10u ", - atomic_read(nmi_counter+cpu_logical_map(j))); + atomic_read(&nmi_counter(cpu_logical_map(j)))); p += sprintf(p, "\n"); #if CONFIG_SMP p += sprintf(p, "LOC: "); @@ -186,7 +183,6 @@ #ifdef CONFIG_SMP unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile int global_irq_lock; -atomic_t global_irq_count; static void show(char * str) { @@ -196,9 +192,9 @@ printk("\n%s, CPU %d:\n", str, cpu); printk("irq: %d [%d %d]\n", - atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]); + irqs_running(), local_irq_count(0), local_irq_count(1)); printk("bh: %d [%d %d]\n", - spin_is_locked(&global_bh_lock) ? 1 : 0, local_bh_count[0], local_bh_count[1]); + spin_is_locked(&global_bh_lock) ? 1 : 0, local_bh_count(0), local_bh_count(1)); stack = (unsigned long *) &stack; for (i = 40; i ; i--) { unsigned long x = *++stack; @@ -248,10 +244,9 @@ * for bottom half handlers unless we're * already executing in one.. */ - if (!atomic_read(&global_irq_count)) { - if (local_bh_count[cpu] || !spin_is_locked(&global_bh_lock)) + if (!irqs_running()) + if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) break; - } /* Duh, we have to loop. Release the lock to avoid deadlocks */ clear_bit(0,&global_irq_lock); @@ -264,11 +259,11 @@ __sti(); SYNC_OTHER_CORES(cpu); __cli(); - if (atomic_read(&global_irq_count)) + if (irqs_running()) continue; if (global_irq_lock) continue; - if (!local_bh_count[cpu] && spin_is_locked(&global_bh_lock)) + if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) continue; if (!test_and_set_bit(0,&global_irq_lock)) break; @@ -285,7 +280,7 @@ */ void synchronize_irq(void) { - if (atomic_read(&global_irq_count)) { + if (irqs_running()) { /* Stupid approach */ cli(); sti(); @@ -338,7 +333,7 @@ if (flags & (1 << EFLAGS_IF_SHIFT)) { int cpu = smp_processor_id(); __cli(); - if (!local_irq_count[cpu]) + if (!local_irq_count(cpu)) get_irqlock(cpu); } } @@ -347,7 +342,7 @@ { int cpu = smp_processor_id(); - if (!local_irq_count[cpu]) + if (!local_irq_count(cpu)) release_irqlock(cpu); __sti(); } @@ -364,6 +359,7 @@ int retval; int local_enabled; unsigned long flags; + int cpu = smp_processor_id(); __save_flags(flags); local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; @@ -371,10 +367,10 @@ retval = 2 + local_enabled; /* check for global flags if we're not in an interrupt */ - if (!local_irq_count[smp_processor_id()]) { + if (!local_irq_count(cpu)) { if (local_enabled) retval = 1; - if (global_irq_holder == (unsigned char) smp_processor_id()) + if (global_irq_holder == cpu) retval = 0; } return retval; @@ -442,16 +438,17 @@ * hardware disable after having gotten the irq * controller lock. */ -void disable_irq_nosync(unsigned int irq) +void inline disable_irq_nosync(unsigned int irq) { + irq_desc_t *desc = irq_desc + irq; unsigned long flags; - spin_lock_irqsave(&irq_controller_lock, flags); - if (!irq_desc[irq].depth++) { - irq_desc[irq].status |= IRQ_DISABLED; - irq_desc[irq].handler->disable(irq); + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); } - spin_unlock_irqrestore(&irq_controller_lock, flags); + spin_unlock_irqrestore(&desc->lock, flags); } /* @@ -462,7 +459,7 @@ { disable_irq_nosync(irq); - if (!local_irq_count[smp_processor_id()]) { + if (!local_irq_count(smp_processor_id())) { do { barrier(); } while (irq_desc[irq].status & IRQ_INPROGRESS); @@ -471,28 +468,29 @@ void enable_irq(unsigned int irq) { + irq_desc_t *desc = irq_desc + irq; unsigned long flags; - spin_lock_irqsave(&irq_controller_lock, flags); - switch (irq_desc[irq].depth) { + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { case 1: { - unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED; - irq_desc[irq].status = status; + unsigned int status = desc->status & ~IRQ_DISABLED; + desc->status = status; if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { - irq_desc[irq].status = status | IRQ_REPLAY; - hw_resend_irq(irq_desc[irq].handler,irq); + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); } - irq_desc[irq].handler->enable(irq); + desc->handler->enable(irq); /* fall-through */ } default: - irq_desc[irq].depth--; + desc->depth--; break; case 0: printk("enable_irq() unbalanced from %p\n", __builtin_return_address(0)); } - spin_unlock_irqrestore(&irq_controller_lock, flags); + spin_unlock_irqrestore(&desc->lock, flags); } /* @@ -514,13 +512,12 @@ */ int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code */ int cpu = smp_processor_id(); - irq_desc_t *desc; + irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status; kstat.irqs[cpu][irq]++; - desc = irq_desc + irq; - spin_lock(&irq_controller_lock); + spin_lock(&desc->lock); desc->handler->ack(irq); /* REPLAY is when Linux resends an IRQ that was dropped earlier @@ -540,7 +537,6 @@ status |= IRQ_INPROGRESS; /* we are handling it */ } desc->status = status; - spin_unlock(&irq_controller_lock); /* * If there is no IRQ handler or it was disabled, exit early. @@ -549,7 +545,7 @@ will take care of it. */ if (!action) - return 1; + goto out; /* * Edge triggered interrupts need to remember @@ -562,20 +558,24 @@ * SMP environment. */ for (;;) { + spin_unlock(&desc->lock); handle_IRQ_event(irq, ®s, action); - spin_lock(&irq_controller_lock); + spin_lock(&desc->lock); if (!(desc->status & IRQ_PENDING)) break; desc->status &= ~IRQ_PENDING; - spin_unlock(&irq_controller_lock); } desc->status &= ~IRQ_INPROGRESS; - if (!(desc->status & IRQ_DISABLED)) - desc->handler->end(irq); - spin_unlock(&irq_controller_lock); +out: + /* + * The ->end() handler has to deal with interrupts which got + * disabled while the handler was running. + */ + desc->handler->end(irq); + spin_unlock(&desc->lock); - if (softirq_state[cpu].active&softirq_state[cpu].mask) + if (softirq_state[cpu].active & softirq_state[cpu].mask) do_softirq(); return 1; } @@ -627,14 +627,16 @@ void free_irq(unsigned int irq, void *dev_id) { + irq_desc_t *desc; struct irqaction **p; unsigned long flags; if (irq >= NR_IRQS) return; - spin_lock_irqsave(&irq_controller_lock,flags); - p = &irq_desc[irq].action; + desc = irq_desc + irq; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; for (;;) { struct irqaction * action = *p; if (action) { @@ -645,22 +647,22 @@ /* Found it - now remove it from the list of entries */ *pp = action->next; - if (!irq_desc[irq].action) { - irq_desc[irq].status |= IRQ_DISABLED; - irq_desc[irq].handler->shutdown(irq); + if (!desc->action) { + desc->status |= IRQ_DISABLED; + desc->handler->shutdown(irq); } - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); #ifdef CONFIG_SMP /* Wait to make sure it's not being used on another CPU */ - while (irq_desc[irq].status & IRQ_INPROGRESS) + while (desc->status & IRQ_INPROGRESS) barrier(); #endif kfree(action); return; } printk("Trying to free free IRQ%d\n",irq); - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); return; } } @@ -676,21 +678,43 @@ unsigned long probe_irq_on(void) { unsigned int i; - unsigned long delay; + irq_desc_t *desc; unsigned long val; + unsigned long delay; + + /* + * something may have generated an irq long ago and we want to + * flush such a longstanding irq before considering it as spurious. + */ + for (i = NR_IRQS-1; i > 0; i--) { + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!irq_desc[i].action) + irq_desc[i].handler->startup(i); + spin_unlock_irq(&desc->lock); + } + + /* Wait for longstanding interrupts to trigger. */ + for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) + /* about 20ms delay */ synchronize_irq(); /* - * first, enable any unassigned irqs + * enable any unassigned irqs + * (we must startup again here because if a longstanding irq + * happened in the previous stage, it may have masked itself) */ - spin_lock_irq(&irq_controller_lock); for (i = NR_IRQS-1; i > 0; i--) { - if (!irq_desc[i].action) { - irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING; - if(irq_desc[i].handler->startup(i)) - irq_desc[i].status |= IRQ_PENDING; + desc = irq_desc + i; + + spin_lock_irq(&desc->lock); + if (!desc->action) { + desc->status |= IRQ_AUTODETECT | IRQ_WAITING; + if (desc->handler->startup(i)) + desc->status |= IRQ_PENDING; } + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); /* * Wait for spurious interrupts to trigger @@ -702,24 +726,24 @@ * Now filter out any obviously spurious interrupts */ val = 0; - spin_lock_irq(&irq_controller_lock); - for (i=0; ishutdown(i); - continue; + for (i = 0; i < NR_IRQS; i++) { + irq_desc_t *desc = irq_desc + i; + unsigned int status; + + spin_lock_irq(&desc->lock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + /* It triggered already - consider it spurious. */ + if (!(status & IRQ_WAITING)) { + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } else + if (i < 32) + val |= 1 << i; } - - if (i < 32) - val |= 1 << i; + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); return val; } @@ -734,20 +758,22 @@ unsigned int mask; mask = 0; - spin_lock_irq(&irq_controller_lock); for (i = 0; i < 16; i++) { - unsigned int status = irq_desc[i].status; + irq_desc_t *desc = irq_desc + i; + unsigned int status; - if (!(status & IRQ_AUTODETECT)) - continue; + spin_lock_irq(&desc->lock); + status = desc->status; - if (!(status & IRQ_WAITING)) - mask |= 1 << i; + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) + mask |= 1 << i; - irq_desc[i].status = status & ~IRQ_AUTODETECT; - irq_desc[i].handler->shutdown(i); + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); + } + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); return mask & val; } @@ -762,22 +788,24 @@ nr_irqs = 0; irq_found = 0; - spin_lock_irq(&irq_controller_lock); - for (i=0; ilock); + status = desc->status; + + if (status & IRQ_AUTODETECT) { + if (!(status & IRQ_WAITING)) { + if (!nr_irqs) + irq_found = i; + nr_irqs++; + } + desc->status = status & ~IRQ_AUTODETECT; + desc->handler->shutdown(i); } - irq_desc[i].status = status & ~IRQ_AUTODETECT; - irq_desc[i].handler->shutdown(i); + spin_unlock_irq(&desc->lock); } - spin_unlock_irq(&irq_controller_lock); if (nr_irqs > 1) irq_found = -irq_found; @@ -788,8 +816,9 @@ int setup_irq(unsigned int irq, struct irqaction * new) { int shared = 0; - struct irqaction *old, **p; unsigned long flags; + struct irqaction *old, **p; + irq_desc_t *desc = irq_desc + irq; /* * Some drivers like serial.c use request_irq() heavily, @@ -811,12 +840,12 @@ /* * The following block of code has to be executed atomically */ - spin_lock_irqsave(&irq_controller_lock,flags); - p = &irq_desc[irq].action; + spin_lock_irqsave(&desc->lock,flags); + p = &desc->action; if ((old = *p) != NULL) { /* Can't share interrupts unless both agree to */ if (!(old->flags & new->flags & SA_SHIRQ)) { - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); return -EBUSY; } @@ -831,11 +860,171 @@ *p = new; if (!shared) { - irq_desc[irq].depth = 0; - irq_desc[irq].status &= ~IRQ_DISABLED; - irq_desc[irq].handler->startup(irq); + desc->depth = 0; + desc->status &= ~IRQ_DISABLED; + desc->handler->startup(irq); } - spin_unlock_irqrestore(&irq_controller_lock,flags); + spin_unlock_irqrestore(&desc->lock,flags); + + register_irq_proc(irq); return 0; +} + +static struct proc_dir_entry * root_irq_dir; +static struct proc_dir_entry * irq_dir [NR_IRQS]; +static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; + +unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff}; + +#define HEX_DIGITS 8 + +static int irq_affinity_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08x\n", irq_affinity[(int)data]); +} + +static unsigned int parse_hex_value (const char *buffer, + unsigned long count, unsigned long *ret) +{ + unsigned char hexnum [HEX_DIGITS]; + unsigned long value; + int i; + + if (!count) + return -EINVAL; + if (count > HEX_DIGITS) + count = HEX_DIGITS; + if (copy_from_user(hexnum, buffer, count)) + return -EFAULT; + + /* + * Parse the first 8 characters as a hex string, any non-hex char + * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. + */ + value = 0; + + for (i = 0; i < count; i++) { + unsigned int c = hexnum[i]; + + switch (c) { + case '0' ... '9': c -= '0'; break; + case 'a' ... 'f': c -= 'a'-10; break; + case 'A' ... 'F': c -= 'A'-10; break; + default: + goto out; + } + value = (value << 4) | c; + } +out: + *ret = value; + return 0; +} + +static int irq_affinity_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int irq = (int) data, full_count = count, err; + unsigned long new_value; + + if (!irq_desc[irq].handler->set_affinity) + return -EIO; + + err = parse_hex_value(buffer, count, &new_value); + +#if CONFIG_SMP + /* + * Do not allow disabling IRQs completely - it's a too easy + * way to make the system unusable accidentally :-) At least + * one online CPU still has to be targeted. + */ + if (!(new_value & cpu_online_map)) + return -EINVAL; +#endif + + irq_affinity[irq] = new_value; + irq_desc[irq].handler->set_affinity(irq, new_value); + + return full_count; +} + +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + unsigned long *mask = (unsigned long *) data; + if (count < HEX_DIGITS+1) + return -EINVAL; + return sprintf (page, "%08lx\n", *mask); +} + +static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, + unsigned long count, void *data) +{ + unsigned long *mask = (unsigned long *) data, full_count = count, err; + unsigned long new_value; + + err = parse_hex_value(buffer, count, &new_value); + if (err) + return err; + + *mask = new_value; + return full_count; +} + +#define MAX_NAMELEN 10 + +static void register_irq_proc (unsigned int irq) +{ + struct proc_dir_entry *entry; + char name [MAX_NAMELEN]; + + if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type)) + return; + + memset(name, 0, MAX_NAMELEN); + sprintf(name, "%d", irq); + + /* create /proc/irq/1234 */ + irq_dir[irq] = proc_mkdir(name, root_irq_dir); + + /* create /proc/irq/1234/smp_affinity */ + entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]); + + entry->nlink = 1; + entry->data = (void *)irq; + entry->read_proc = irq_affinity_read_proc; + entry->write_proc = irq_affinity_write_proc; + + smp_affinity_entry[irq] = entry; +} + +unsigned long prof_cpu_mask = -1; + +void init_irq_proc (void) +{ + struct proc_dir_entry *entry; + int i; + + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", 0); + + /* create /proc/irq/prof_cpu_mask */ + entry = create_proc_entry("prof_cpu_mask", 0700, root_irq_dir); + + entry->nlink = 1; + entry->data = (void *)&prof_cpu_mask; + entry->read_proc = prof_cpu_mask_read_proc; + entry->write_proc = prof_cpu_mask_write_proc; + + /* + * Create entries for all existing IRQs. + */ + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc[i].handler == &no_irq_type) + continue; + register_irq_proc(i); + } } diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/microcode.c linux/arch/i386/kernel/microcode.c --- v2.3.47/linux/arch/i386/kernel/microcode.c Sun Feb 20 21:12:38 2000 +++ linux/arch/i386/kernel/microcode.c Sat Feb 26 20:33:02 2000 @@ -20,6 +20,9 @@ * Initial release. * 1.01 18 February 2000, Tigran Aivazian * Added read() support + cleanups. + * 1.02 21 February 2000, Tigran Aivazian + * Added 'device trimming' support. open(O_WRONLY) zeroes + * and frees the saved copy of applied microcode. */ #include @@ -33,7 +36,7 @@ #include #include -#define MICROCODE_VERSION "1.01" +#define MICROCODE_VERSION "1.02" MODULE_DESCRIPTION("CPU (P6) microcode update driver"); MODULE_AUTHOR("Tigran Aivazian "); @@ -53,7 +56,7 @@ /* * Bits in microcode_status. (31 bits of room for future expansion) */ -#define MICROCODE_IS_OPEN 0 /* set if /dev/microcode is in use */ +#define MICROCODE_IS_OPEN 0 /* set if device is in use */ static unsigned long microcode_status = 0; /* the actual array of microcode blocks, each 2048 bytes */ @@ -68,31 +71,16 @@ release: microcode_release, }; -static struct inode_operations microcode_inops = { - default_file_ops: µcode_fops, -}; - static struct proc_dir_entry *proc_microcode; static int __init microcode_init(void) { - int size; - proc_microcode = create_proc_entry("microcode", S_IWUSR|S_IRUSR, proc_root_driver); if (!proc_microcode) { printk(KERN_ERR "microcode: can't create /proc/driver/microcode\n"); return -ENOMEM; } - proc_microcode->ops = µcode_inops; - size = smp_num_cpus * sizeof(struct microcode); - mc_applied = kmalloc(size, GFP_KERNEL); - if (!mc_applied) { - remove_proc_entry("microcode", proc_root_driver); - printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n"); - return -ENOMEM; - } - memset(mc_applied, 0, size); /* so that reading from offsets corresponding to failed - update makes this obvious */ + proc_microcode->proc_fops = µcode_fops; printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION); return 0; } @@ -100,7 +88,8 @@ static void __exit microcode_exit(void) { remove_proc_entry("microcode", proc_root_driver); - kfree(mc_applied); + if (mc_applied) + kfree(mc_applied); printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION); } @@ -119,6 +108,15 @@ if (test_and_set_bit(MICROCODE_IS_OPEN, µcode_status)) return -EBUSY; + if ((file->f_flags & O_ACCMODE) == O_WRONLY) { + proc_microcode->size = 0; + if (mc_applied) { + memset(mc_applied, 0, smp_num_cpus * sizeof(struct microcode)); + kfree(mc_applied); + mc_applied = NULL; + } + } + MOD_INC_USE_COUNT; return 0; @@ -243,6 +241,16 @@ sizeof(struct microcode)); return -EINVAL; } + if (!mc_applied) { + int size = smp_num_cpus * sizeof(struct microcode); + mc_applied = kmalloc(size, GFP_KERNEL); + if (!mc_applied) { + printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n"); + return -ENOMEM; + } + memset(mc_applied, 0, size); + } + lock_kernel(); microcode_num = len/sizeof(struct microcode); microcode = vmalloc(len); diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/mpparse.c linux/arch/i386/kernel/mpparse.c --- v2.3.47/linux/arch/i386/kernel/mpparse.c Sat Feb 12 11:22:10 2000 +++ linux/arch/i386/kernel/mpparse.c Sat Feb 26 08:13:45 2000 @@ -316,11 +316,14 @@ return num_processors; } +static struct intel_mp_floating *mpf_found; + /* * Scan the memory blocks for an SMP configuration block. */ -static int __init smp_get_mpf(struct intel_mp_floating *mpf) +void __init get_smp_config (void) { + struct intel_mp_floating *mpf = mpf_found; printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); if (mpf->mpf_feature2 & (1<<7)) { printk(" IMCR and PIC compatibility mode.\n"); @@ -329,7 +332,6 @@ printk(" Virtual Wire compatibility mode.\n"); pic_mode = 0; } - smp_found_config = 1; /* * default CPU id - if it's different in the mptable * then we change it before first using it. @@ -388,7 +390,7 @@ default: printk("???\nUnknown standard configuration %d\n", mpf->mpf_feature1); - return 1; + return; } if (mpf->mpf_feature1 > 4) { printk("Bus #1 is PCI\n"); @@ -412,10 +414,9 @@ /* * Only use the first configuration found. */ - return 1; } -static int __init smp_scan_config(unsigned long base, unsigned long length) +static int __init smp_scan_config (unsigned long base, unsigned long length) { unsigned long *bp = phys_to_virt(base); struct intel_mp_floating *mpf; @@ -432,9 +433,13 @@ ((mpf->mpf_specification == 1) || (mpf->mpf_specification == 4)) ) { - printk("found SMP MP-table at %08ld\n", + smp_found_config = 1; + printk("found SMP MP-table at %08lx\n", virt_to_phys(mpf)); - smp_get_mpf(mpf); + reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE); + if (mpf->mpf_physptr) + reserve_bootmem(mpf->mpf_physptr, PAGE_SIZE); + mpf_found = mpf; return 1; } bp += 4; @@ -443,7 +448,7 @@ return 0; } -void __init init_intel_smp (void) +void __init find_intel_smp (void) { unsigned int address; @@ -488,7 +493,7 @@ * sense, but it doesnt have a BIOS(-configuration table). * No problem for Linux. */ -void __init init_visws_smp(void) +void __init find_visws_smp(void) { smp_found_config = 1; @@ -505,13 +510,13 @@ * - Intel MP Configuration Table * - or SGI Visual Workstation configuration */ -void __init init_smp_config (void) +void __init find_smp_config (void) { #ifdef CONFIG_X86_IO_APIC - init_intel_smp(); + find_intel_smp(); #endif #ifdef CONFIG_VISWS - init_visws_smp(); + find_visws_smp(); #endif } diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.3.47/linux/arch/i386/kernel/mtrr.c Sun Feb 20 21:12:38 2000 +++ linux/arch/i386/kernel/mtrr.c Sat Feb 26 20:33:02 2000 @@ -1507,11 +1507,6 @@ # ifdef CONFIG_PROC_FS -static struct inode_operations proc_mtrr_inode_operations = -{ - &mtrr_fops, /* default property file-ops */ -}; - static struct proc_dir_entry *proc_root_mtrr; # endif /* CONFIG_PROC_FS */ @@ -1836,9 +1831,9 @@ #ifdef CONFIG_PROC_FS proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); - proc_root_mtrr->ops = &proc_mtrr_inode_operations; + proc_root_mtrr->proc_fops = &mtrr_fops; #endif -#ifdev CONFIG_DEVFS_FS +#ifdef CONFIG_DEVFS_FS devfs_handle = devfs_register (NULL, "cpu/mtrr", 0, DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUGO | S_IWUSR, 0, 0, &mtrr_fops, NULL); diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.3.47/linux/arch/i386/kernel/process.c Sun Feb 20 21:12:38 2000 +++ linux/arch/i386/kernel/process.c Thu Feb 24 22:41:15 2000 @@ -74,8 +74,13 @@ */ static void default_idle(void) { - if (current_cpu_data.hlt_works_ok && !hlt_counter) - asm volatile("sti ; hlt" : : : "memory"); + if (current_cpu_data.hlt_works_ok && !hlt_counter) { + asm volatile("cli" : : : "memory"); + if (!current->need_resched) + asm volatile("sti ; hlt" : : : "memory"); + else + asm volatile("sti" : : : "memory"); + } } /* diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/semaphore.c linux/arch/i386/kernel/semaphore.c --- v2.3.47/linux/arch/i386/kernel/semaphore.c Tue Dec 7 09:32:40 1999 +++ linux/arch/i386/kernel/semaphore.c Fri Feb 25 16:35:28 2000 @@ -150,8 +150,9 @@ int __down_trylock(struct semaphore * sem) { int sleepers; + unsigned long flags; - spin_lock_irq(&semaphore_lock); + spin_lock_irqsave(&semaphore_lock, flags); sleepers = sem->sleepers + 1; sem->sleepers = 0; @@ -162,7 +163,7 @@ if (!atomic_add_negative(sleepers, &sem->count)) wake_up(&sem->wait); - spin_unlock_irq(&semaphore_lock); + spin_unlock_irqrestore(&semaphore_lock, flags); return 1; } diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.47/linux/arch/i386/kernel/setup.c Sat Feb 12 11:22:10 2000 +++ linux/arch/i386/kernel/setup.c Fri Feb 25 15:15:54 2000 @@ -119,7 +119,7 @@ #endif extern int root_mountflags; -extern int _text, _etext, _edata, _end; +extern char _text, _etext, _edata, _end; extern unsigned long cpu_hz; /* @@ -709,9 +709,20 @@ #ifdef CONFIG_X86_IO_APIC /* - * Save possible boot-time SMP configuration: + * Find and reserve possible boot-time SMP configuration: */ - init_smp_config(); + find_smp_config(); +#endif + paging_init(); +#ifdef CONFIG_X86_IO_APIC + /* + * get boot-time SMP configuration: + */ + if (smp_found_config) + get_smp_config(); +#endif +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); #endif #ifdef CONFIG_BLK_DEV_INITRD diff -u --recursive --new-file v2.3.47/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.3.47/linux/arch/i386/kernel/traps.c Thu Feb 10 17:11:03 2000 +++ linux/arch/i386/kernel/traps.c Thu Feb 24 22:41:16 2000 @@ -360,8 +360,6 @@ printk("Do you have a strange power saving mode enabled?\n"); } -atomic_t nmi_counter[NR_CPUS]; - #if CONFIG_X86_IO_APIC int nmi_watchdog = 1; @@ -437,7 +435,8 @@ { unsigned char reason = inb(0x61); - atomic_inc(nmi_counter+smp_processor_id()); + + atomic_inc(&nmi_counter(smp_processor_id())); if (!(reason & 0xc0)) { #if CONFIG_X86_IO_APIC /* diff -u --recursive --new-file v2.3.47/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v2.3.47/linux/arch/i386/mm/init.c Wed Feb 16 17:03:51 2000 +++ linux/arch/i386/mm/init.c Fri Feb 25 15:15:54 2000 @@ -438,10 +438,6 @@ __flush_tlb_all(); -#ifdef CONFIG_X86_LOCAL_APIC - init_apic_mappings(); -#endif - #ifdef CONFIG_HIGHMEM kmap_init(); #endif diff -u --recursive --new-file v2.3.47/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c --- v2.3.47/linux/arch/ia64/ia32/binfmt_elf32.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/ia32/binfmt_elf32.c Thu Feb 24 10:14:29 2000 @@ -82,6 +82,8 @@ /* Do all the IA-32 setup here */ + current->thread.map_base = 0x40000000; + /* CS descriptor */ __asm__("mov ar.csd = %0" : /* no outputs */ : "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L, diff -u --recursive --new-file v2.3.47/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S --- v2.3.47/linux/arch/ia64/ia32/ia32_entry.S Sun Feb 13 19:29:03 2000 +++ linux/arch/ia64/ia32/ia32_entry.S Thu Feb 24 10:14:29 2000 @@ -75,7 +75,7 @@ data8 sys_unlink /* 10 */ data8 sys32_execve data8 sys_chdir - data8 sys_ni_syscall /* sys_time is not supported on ia64 */ + data8 sys32_time data8 sys_mknod data8 sys_chmod /* 15 */ data8 sys_lchown diff -u --recursive --new-file v2.3.47/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.3.47/linux/arch/ia64/ia32/sys_ia32.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ia64/ia32/sys_ia32.c Sat Feb 26 20:33:02 2000 @@ -278,7 +278,7 @@ if (!file) return -EINVAL; inode = file->f_dentry->d_inode; - if (!inode->i_op || !inode->i_op->default_file_ops) + if (!inode->i_fop) return -EINVAL; if (!file->f_op->read) return -EINVAL; @@ -1928,6 +1928,25 @@ out: unlock_kernel(); return err; +} + +/* + * sys_time() can be implemented in user-level using + * sys_gettimeofday(). IA64 did this but i386 Linux did not + * so we have to implement this system call here. + */ +asmlinkage long sys32_time(int * tloc) +{ + int i; + + /* SMP: This is fairly trivial. We grab CURRENT_TIME and + stuff it to user space. No side effects */ + i = CURRENT_TIME; + if (tloc) { + if (put_user(i,tloc)) + i = -EFAULT; + } + return i; } #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ diff -u --recursive --new-file v2.3.47/linux/arch/ia64/kdb/kdbsupport.c linux/arch/ia64/kdb/kdbsupport.c --- v2.3.47/linux/arch/ia64/kdb/kdbsupport.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kdb/kdbsupport.c Thu Feb 24 10:14:29 2000 @@ -28,9 +28,10 @@ #include #include -#include +#include #include #include +#include extern kdb_state_t kdb_state ; k_machreg_t dbregs[KDB_DBREGS]; @@ -45,6 +46,21 @@ __setup("kdb", kdb_setup); static int +kdb_ia64_itm (int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + unsigned long val; + + diag = kdbgetularg(argv[1], &val); + if (diag) + return diag; + kdb_printf("new itm=%0xlx\n", val); + + ia64_set_itm(val); + return 0; +} + +static int kdb_ia64_sir (int argc, const char **argv, const char **envp, struct pt_regs *regs) { u64 lid, tpr, lrr0, lrr1, itv, pmv, cmcv; @@ -53,15 +69,17 @@ asm ("mov %0=cr.tpr" : "=r"(tpr)); asm ("mov %0=cr.lrr0" : "=r"(lrr0)); asm ("mov %0=cr.lrr1" : "=r"(lrr1)); - printk ("lid=0x%lx, tpr=0x%lx, lrr0=0x%lx, llr1=0x%lx\n", lid, tpr, lrr0, lrr1); + printk("lid=0x%lx, tpr=0x%lx, lrr0=0x%lx, llr1=0x%lx\n", lid, tpr, lrr0, lrr1); asm ("mov %0=cr.itv" : "=r"(itv)); asm ("mov %0=cr.pmv" : "=r"(pmv)); asm ("mov %0=cr.cmcv" : "=r"(cmcv)); - printk ("itv=0x%lx, pmv=0x%lx, cmcv=0x%lx\n", itv, pmv, cmcv); + printk("itv=0x%lx, pmv=0x%lx, cmcv=0x%lx\n", itv, pmv, cmcv); - printk ("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n", + printk("irr=0x%016lx,0x%016lx,0x%016lx,0x%016lx\n", ia64_get_irr0(), ia64_get_irr1(), ia64_get_irr2(), ia64_get_irr3()); + + printk("itc=0x%016lx, itm=0x%016lx\n", ia64_get_itc(), ia64_get_itm()); return 0; } @@ -90,6 +108,7 @@ kdb_state.bkpt_handling_state = BKPTSTATE_NOT_HANDLED ; kdb_register("irr", kdb_ia64_sir, "", "Show interrupt registers", 0); + kdb_register("itm", kdb_ia64_itm, "", "Set new ITM value", 0); } /* diff -u --recursive --new-file v2.3.47/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c --- v2.3.47/linux/arch/ia64/kernel/irq.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ia64/kernel/irq.c Thu Feb 24 10:14:29 2000 @@ -158,6 +158,9 @@ unsigned long eoi_ptr; # ifdef CONFIG_USB + extern void reenable_usb (void); + extern void disable_usb (void); + if (usbfix) disable_usb(); # endif diff -u --recursive --new-file v2.3.47/linux/arch/ia64/kernel/irq_internal.c linux/arch/ia64/kernel/irq_internal.c --- v2.3.47/linux/arch/ia64/kernel/irq_internal.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/irq_internal.c Thu Feb 24 10:14:29 2000 @@ -60,7 +60,7 @@ } struct hw_interrupt_type irq_type_ia64_internal = { - "IA64 internal", + "IA64-internal", (void (*)(unsigned long)) internal_noop, /* init */ internal_noop, /* startup */ internal_noop, /* shutdown */ diff -u --recursive --new-file v2.3.47/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S --- v2.3.47/linux/arch/ia64/kernel/ivt.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/ivt.S Thu Feb 24 10:14:29 2000 @@ -1026,7 +1026,7 @@ // 0x5000 Entry 20 (size 16 bundles) Page Not Present (10,22,49) mov r16=cr.ifa rsm psr.dt -#if 0 +#if 1 // If you disable this, you MUST re-enable to update_mmu_cache() code in pgtable.h mov r17=_PAGE_SIZE_4K<<2 ;; diff -u --recursive --new-file v2.3.47/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c --- v2.3.47/linux/arch/ia64/kernel/process.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/process.c Thu Feb 24 10:14:29 2000 @@ -97,6 +97,14 @@ check_pgt_cache(); if (pm_idle) (*pm_idle)(); +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + if (ia64_get_itm() < ia64_get_itc()) { + extern void ia64_reset_itm(); + + printk("cpu_idle: ITM in past, resetting it...\n"); + ia64_reset_itm(); + } +#endif } } diff -u --recursive --new-file v2.3.47/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c --- v2.3.47/linux/arch/ia64/kernel/time.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/time.c Thu Feb 24 10:14:29 2000 @@ -21,6 +21,10 @@ #include #include #include +#ifdef CONFIG_KDB +# include +#endif + extern rwlock_t xtime_lock; extern volatile unsigned long lost_ticks; @@ -61,7 +65,7 @@ * update to jiffy. The xtime_lock must be at least read-locked when * calling this routine. */ -static inline unsigned long +static /*inline*/ unsigned long gettimeoffset (void) { unsigned long now = ia64_get_itc(); @@ -185,6 +189,20 @@ } write_unlock(&xtime_lock); } + +#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC + +void +ia64_reset_itm (void) +{ + unsigned long flags; + + local_irq_save(flags); + timer_interrupt(0, 0, current); + local_irq_restore(flags); +} + +#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ /* * Encapsulate access to the itm structure for SMP. diff -u --recursive --new-file v2.3.47/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c --- v2.3.47/linux/arch/ia64/kernel/traps.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/traps.c Thu Feb 24 10:14:29 2000 @@ -110,15 +110,75 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs) { siginfo_t siginfo; + int sig, code; - /* gdb uses a break number of 0xccccc for debug breakpoints: */ - if (break_num != 0xccccc) - die_if_kernel("Bad break", regs, break_num); - - siginfo.si_signo = SIGTRAP; - siginfo.si_errno = break_num; /* XXX is it legal to abuse si_errno like this? */ - siginfo.si_code = TRAP_BRKPT; - send_sig_info(SIGTRAP, &siginfo, current); + /* 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; + + switch (break_num) { + case 0: /* unknown error */ + sig = SIGILL; code = ILL_ILLOPC; + break; + + case 1: /* integer divide by zero */ + sig = SIGFPE; code = FPE_INTDIV; + break; + + case 2: /* integer overflow */ + sig = SIGFPE; code = FPE_INTOVF; + break; + + case 3: /* range check/bounds check */ + sig = SIGFPE; code = FPE_FLTSUB; + break; + + case 4: /* null pointer dereference */ + sig = SIGSEGV; code = SEGV_MAPERR; + break; + + case 5: /* misaligned data */ + sig = SIGSEGV; code = BUS_ADRALN; + break; + + case 6: /* decimal overflow */ + sig = SIGFPE; code = __FPE_DECOVF; + break; + + case 7: /* decimal divide by zero */ + sig = SIGFPE; code = __FPE_DECDIV; + break; + + case 8: /* packed decimal error */ + sig = SIGFPE; code = __FPE_DECERR; + break; + + case 9: /* invalid ASCII digit */ + sig = SIGFPE; code = __FPE_INVASC; + break; + + case 10: /* invalid decimal digit */ + sig = SIGFPE; code = __FPE_INVDEC; + break; + + case 11: /* paragraph stack overflow */ + sig = SIGSEGV; code = __SEGV_PSTKOVF; + break; + + default: + if (break_num < 0x40000 || break_num > 0x100000) + die_if_kernel("Bad break", regs, break_num); + + if (break_num < 0x80000) { + sig = SIGILL; code = __ILL_BREAK; + } else { + sig = SIGTRAP; code = TRAP_BRKPT; + } + } + siginfo.si_signo = sig; + siginfo.si_errno = 0; + siginfo.si_code = code; + send_sig_info(sig, &siginfo, current); } /* @@ -240,6 +300,7 @@ { long exception, bundle[2]; unsigned long fault_ip; + struct siginfo siginfo; static int fpu_swa_count = 0; static unsigned long last_time; @@ -265,21 +326,41 @@ ia64_increment_ip(regs); } else if (exception == -1) { printk("handle_fpu_swa: fp_emulate() returned -1\n"); - return -2; + return -1; } else { /* is next instruction a trap? */ if (exception & 2) { ia64_increment_ip(regs); } - return -1; + siginfo.si_signo = SIGFPE; + siginfo.si_errno = 0; + siginfo.si_code = 0; + siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + if (isr & 0x11) { + siginfo.si_code = FPE_FLTINV; + } else if (isr & 0x44) { + siginfo.si_code = FPE_FLTDIV; + } + send_sig_info(SIGFPE, &siginfo, current); } } else { if (exception == -1) { printk("handle_fpu_swa: fp_emulate() returned -1\n"); - return -2; + return -1; } else if (exception != 0) { /* raise exception */ - return -1; + siginfo.si_signo = SIGFPE; + siginfo.si_errno = 0; + siginfo.si_code = 0; + siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); + if (isr & 0x880) { + siginfo.si_code = FPE_FLTOVF; + } else if (isr & 0x1100) { + siginfo.si_code = FPE_FLTUND; + } else if (isr & 0x2200) { + siginfo.si_code = FPE_FLTRES; + } + send_sig_info(SIGFPE, &siginfo, current); } } return 0; @@ -369,22 +450,19 @@ return; case 30: /* Unaligned fault */ - sprintf(buf, "Unaligned access in kernel mode---don't do this!"); + sprintf(buf, "Kernel unaligned trap accessing %016lx (ip=%016lx)!", + ifa, regs->cr_iip + ia64_psr(regs)->ri); break; case 32: /* fp fault */ case 33: /* fp trap */ - result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr); + result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, &isr); if (result < 0) { siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; - siginfo.si_code = 0; /* XXX fix me */ + siginfo.si_code = FPE_FLTINV; siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); - send_sig_info(SIGFPE, &siginfo, current); - if (result == -1) - send_sig_info(SIGFPE, &siginfo, current); - else - force_sig(SIGFPE, current); + force_sig(SIGFPE, current); } return; diff -u --recursive --new-file v2.3.47/linux/arch/ia64/kernel/unaligned.c linux/arch/ia64/kernel/unaligned.c --- v2.3.47/linux/arch/ia64/kernel/unaligned.c Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/kernel/unaligned.c Thu Feb 24 10:14:29 2000 @@ -1384,30 +1384,33 @@ load_store_t *insn; int ret = -1; - /* - * We flag unaligned references while in kernel as - * errors: the kernel must be fixed. The switch code - * is in ivt.S at entry 30. - * - * So here we keep a simple sanity check. - */ - if ( !user_mode(regs) ) { - die_if_kernel("Unaligned reference while in kernel\n", regs, 30); - /* NOT_REACHED */ + if (current->thread.flags & IA64_THREAD_UAC_SIGBUS) { + struct siginfo si; + + si.si_signo = SIGBUS; + si.si_errno = 0; + si.si_code = BUS_ADRALN; + si.si_addr = (void *) ifa; + send_sig_info (SIGBUS, &si, current); + return; } - /* - * Make sure we log the unaligned access, so that user/sysadmin can notice it - * and eventually fix the program. - * - * We don't want to do that for every access so we pace it with jiffies. - */ - if ( unalign_count > 5 && jiffies - last_time > 5*HZ ) unalign_count = 0; - if ( ++unalign_count < 5 ) { - last_time = jiffies; - printk("%s(%d): unaligned trap accessing %016lx (ip=%016lx)\n", - current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); - + if (!(current->thread.flags & IA64_THREAD_UAC_NOPRINT)) { + /* + * Make sure we log the unaligned access, so that + * user/sysadmin can notice it and eventually fix the + * program. + * + * We don't want to do that for every access so we + * pace it with jiffies. + */ + if (unalign_count > 5 && jiffies - last_time > 5*HZ) + unalign_count = 0; + if (++unalign_count < 5) { + last_time = jiffies; + printk("%s(%d): unaligned trap accessing %016lx (ip=%016lx)\n", + current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); + } } DPRINT(("iip=%lx ifa=%lx isr=%lx\n", regs->cr_iip, ifa, regs->cr_ipsr)); diff -u --recursive --new-file v2.3.47/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S --- v2.3.47/linux/arch/ia64/lib/copy_user.S Thu Feb 10 17:11:03 2000 +++ linux/arch/ia64/lib/copy_user.S Thu Feb 24 10:14:29 2000 @@ -1,71 +1,375 @@ -/* - * This routine copies a linear memory buffer across the user/kernel boundary. When - * reading a byte from the source causes a fault, the remainder of the destination - * buffer is zeroed out. Note that this can happen only when copying from user - * to kernel memory and we do this to absolutely guarantee that the - * kernel doesn't operate on random data. - * - * This file is derived from arch/alpha/lib/copy_user.S. - * - * Inputs: - * in0: address of destination buffer - * in1: address of source buffer - * in2: length of buffer in bytes - * Outputs: - * r8: number of bytes that didn't get copied due to a fault - * - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1998, 1999 David Mosberger-Tang - */ - -#define EXI(x...) \ -99: x; \ +// The label comes first because our store instruction contains a comma +// and confuse the preprocessor otherwise +// +#undef DEBUG +#ifdef DEBUG +#define EX(y,x...) \ +99: x +#else +#define EX(y,x...) \ .section __ex_table,"a"; \ - data4 @gprel(99b); \ - data4 .Lexit_in-99b; \ - .previous + data4 @gprel(99f); \ + data4 y-99f; \ + .previous; \ +99: x +#endif -#define EXO(x...) \ -99: x; \ - .section __ex_table,"a"; \ - data4 @gprel(99b); \ - data4 .Lexit_out-99b; \ - .previous - - .text - .psr abi64 - .psr lsb - .lsb - - .align 32 - .global __copy_user - .proc __copy_user +// +// Tuneable parameters +// +#define COPY_BREAK 16 // we do byte copy below (must be >=16) +#define PIPE_DEPTH 4 // pipe depth + +#define EPI p[PIPE_DEPTH-1] // PASTE(p,16+PIPE_DEPTH-1) + +// +// arguments +// +#define dst in0 +#define src in1 +#define len in2 + +// +// local registers +// +#define cnt r18 +#define len2 r19 +#define saved_lc r20 +#define saved_pr r21 +#define tmp r22 +#define val r23 +#define src1 r24 +#define dst1 r25 +#define src2 r26 +#define dst2 r27 +#define len1 r28 +#define enddst r29 +#define endsrc r30 +#define saved_pfs r31 + .text + .psr abi64 + .psr lsb + + .align 16 + .global __copy_user + .proc __copy_user __copy_user: - alloc r10=ar.pfs,3,0,0,0 - mov r9=ar.lc // save ar.lc - mov ar.lc=in2 // set ar.lc to length of buffer - br.sptk.few .Lentr - - // XXX braindead copy loop---this needs to be optimized -.Loop1: - EXI(ld1 r8=[in1],1) - ;; - EXO(st1 [in0]=r8,1) -.Lentr: br.cloop.dptk.few .Loop1 // repeat unless ar.lc--==0 - ;; // avoid RAW on ar.lc -.Lexit_out: - mov r8=ar.lc // return how many bytes we _didn't_ copy - mov ar.lc=r9 - br.ret.sptk.few rp - -.Lexit_in: - // clear the remainder of the buffer: - mov r8=ar.lc // return how many bytes we _didn't_ copy -.Loop2: - st1 [in0]=r0,1 // this cannot fault because we get here only on user->kernel copies - br.cloop.dptk.few .Loop2 - ;; // avoid RAW on ar.lc - mov ar.lc=r9 - br.ret.sptk.few rp + alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7) + + .rotr val1[PIPE_DEPTH],val2[PIPE_DEPTH] + .rotp p[PIPE_DEPTH] + + adds len2=-1,len // br.ctop is repeat/until + mov ret0=r0 + + ;; // RAW of cfm when len=0 + cmp.eq p8,p0=r0,len // check for zero length + mov saved_lc=ar.lc // preserve ar.lc (slow) +(p8) br.ret.spnt.few rp // empty mempcy() + ;; + add enddst=dst,len // first byte after end of source + add endsrc=src,len // first byte after end of destination + mov saved_pr=pr // preserve predicates + + mov dst1=dst // copy because of rotation + mov ar.ec=PIPE_DEPTH + mov pr.rot=1<<16 // p16=true all others are false + + mov src1=src // copy because of rotation + mov ar.lc=len2 // initialize lc for small count + cmp.lt p10,p7=COPY_BREAK,len // if len > COPY_BREAK then long copy + + xor tmp=src,dst // same alignment test prepare +(p10) br.cond.dptk.few long_memcpy + ;; // RAW pr.rot/p16 ? + // + // Now we do the byte by byte loop with software pipeline + // + // p7 is necessarily false by now +1: + EX(failure_in_pipe1,(p16) ld1 val1[0]=[src1],1) + + EX(failure_out,(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1) + br.ctop.dptk.few 1b + ;; + mov ar.lc=saved_lc + mov pr=saved_pr,0xffffffffffff0000 + mov ar.pfs=saved_pfs // restore ar.ec + br.ret.sptk.few rp // end of short memcpy + + // + // Beginning of long mempcy (i.e. > 16 bytes) + // +long_memcpy: + tbit.nz p6,p7=src1,0 // odd alignement + and tmp=7,tmp + ;; + cmp.eq p10,p8=r0,tmp + mov len1=len // copy because of rotation +(p8) br.cond.dpnt.few 1b // XXX Fixme. memcpy_diff_align + ;; + // At this point we know we have more than 16 bytes to copy + // and also that both src and dest have the same alignment + // which may not be the one we want. So for now we must move + // forward slowly until we reach 16byte alignment: no need to + // worry about reaching the end of buffer. + // + EX(failure_in1,(p6) ld1 val1[0]=[src1],1) // 1-byte aligned +(p6) adds len1=-1,len1;; + tbit.nz p7,p0=src1,1 + ;; + EX(failure_in1,(p7) ld2 val1[1]=[src1],2) // 2-byte aligned +(p7) adds len1=-2,len1;; + tbit.nz p8,p0=src1,2 + ;; + // + // Stop bit not required after ld4 because if we fail on ld4 + // we have never executed the ld1, therefore st1 is not executed. + // + EX(failure_in1,(p8) ld4 val2[0]=[src1],4) // 4-byte aligned + EX(failure_out,(p6) st1 [dst1]=val1[0],1) + tbit.nz p9,p0=src1,3 + ;; + // + // Stop bit not required after ld8 because if we fail on ld8 + // we have never executed the ld2, therefore st2 is not executed. + // + EX(failure_in1,(p9) ld8 val2[1]=[src1],8) // 8-byte aligned + EX(failure_out,(p7) st2 [dst1]=val1[1],2) +(p8) adds len1=-4,len1 + ;; + EX(failure_out, (p8) st4 [dst1]=val2[0],4) +(p9) adds len1=-8,len1;; + shr.u cnt=len1,4 // number of 128-bit (2x64bit) words + ;; + EX(failure_out, (p9) st8 [dst1]=val2[1],8) + tbit.nz p6,p0=len1,3 + cmp.eq p7,p0=r0,cnt + adds tmp=-1,cnt // br.ctop is repeat/until +(p7) br.cond.dpnt.few .dotail // we have less than 16 bytes left + ;; + adds src2=8,src1 + adds dst2=8,dst1 + mov ar.lc=tmp + ;; + // + // 16bytes/iteration + // +2: + EX(failure_in3,(p16) ld8 val1[0]=[src1],16) +(p16) ld8 val2[0]=[src2],16 + + EX(failure_out, (EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16) +(EPI) st8 [dst2]=val2[PIPE_DEPTH-1],16 + br.ctop.dptk.few 2b + ;; // RAW on src1 when fall through from loop + // + // Tail correction based on len only + // + // No matter where we come from (loop or test) the src1 pointer + // is 16 byte aligned AND we have less than 16 bytes to copy. + // +.dotail: + EX(failure_in1,(p6) ld8 val1[0]=[src1],8) // at least 8 bytes + tbit.nz p7,p0=len1,2 + ;; + EX(failure_in1,(p7) ld4 val1[1]=[src1],4) // at least 4 bytes + tbit.nz p8,p0=len1,1 + ;; + EX(failure_in1,(p8) ld2 val2[0]=[src1],2) // at least 2 bytes + tbit.nz p9,p0=len1,0 + ;; + EX(failure_out, (p6) st8 [dst1]=val1[0],8) + ;; + EX(failure_in1,(p9) ld1 val2[1]=[src1]) // only 1 byte left + mov ar.lc=saved_lc + ;; + EX(failure_out,(p7) st4 [dst1]=val1[1],4) + mov pr=saved_pr,0xffffffffffff0000 + ;; + EX(failure_out, (p8) st2 [dst1]=val2[0],2) + mov ar.pfs=saved_pfs + ;; + EX(failure_out, (p9) st1 [dst1]=val2[1]) + br.ret.dptk.few rp + + + + // + // Here we handle the case where the byte by byte copy fails + // on the load. + // Several factors make the zeroing of the rest of the buffer kind of + // tricky: + // - the pipeline: loads/stores are not in sync (pipeline) + // + // In the same loop iteration, the dst1 pointer does not directly + // reflect where the faulty load was. + // + // - pipeline effect + // When you get a fault on load, you may have valid data from + // previous loads not yet store in transit. Such data must be + // store normally before moving onto zeroing the rest. + // + // - single/multi dispersal independence. + // + // solution: + // - we don't disrupt the pipeline, i.e. data in transit in + // the software pipeline will be eventually move to memory. + // We simply replace the load with a simple mov and keep the + // pipeline going. We can't really do this inline because + // p16 is always reset to 1 when lc > 0. + // +failure_in_pipe1: + sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied +1: +(p16) mov val1[0]=r0 +(EPI) st1 [dst1]=val1[PIPE_DEPTH-1],1 + br.ctop.dptk.few 1b + ;; + mov pr=saved_pr,0xffffffffffff0000 + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs + br.ret.dptk.few rp + + + // + // Here we handle the head & tail part when we check for alignment. + // The following code handles only the load failures. The + // main diffculty comes from the fact that loads/stores are + // scheduled. So when you fail on a load, the stores corresponding + // to previous successful loads must be executed. + // + // However some simplifications are possible given the way + // things work. + // + // 1) HEAD + // Theory of operation: + // + // Page A | Page B + // ---------|----- + // 1|8 x + // 1 2|8 x + // 4|8 x + // 1 4|8 x + // 2 4|8 x + // 1 2 4|8 x + // |1 + // |2 x + // |4 x + // + // page_size >= 4k (2^12). (x means 4, 2, 1) + // Here we suppose Page A exists and Page B does not. + // + // As we move towards eight byte alignment we may encounter faults. + // The numbers on each page show the size of the load (current alignment). + // + // Key point: + // - if you fail on 1, 2, 4 then you have never executed any smaller + // size loads, e.g. failing ld4 means no ld1 nor ld2 executed + // before. + // + // This allows us to simplify the cleanup code, because basically you + // only have to worry about "pending" stores in the case of a failing + // ld8(). Given the way the code is written today, this means only + // worry about st2, st4. There we can use the information encapsulated + // into the predicates. + // + // Other key point: + // - if you fail on the ld8 in the head, it means you went straight + // to it, i.e. 8byte alignment within an unexisting page. + // Again this comes from the fact that if you crossed just for the the ld8 then + // you are 8byte aligned but also 16byte align, therefore you would + // either go for the 16byte copy loop OR the ld8 in the tail part. + // The combination ld1, ld2, ld4, ld8 where you fail on ld8 is impossible + // because it would mean you had 15bytes to copy in which case you + // would have defaulted to the byte by byte copy. + // + // + // 2) TAIL + // Here we now we have less than 16 bytes AND we are either 8 or 16 byte + // aligned. + // + // Key point: + // This means that we either: + // - are right on a page boundary + // OR + // - are at more than 16 bytes from a page boundary with + // at most 15 bytes to copy: no chance of crossing. + // + // This allows us to assume that if we fail on a load we haven't possibly + // executed any of the previous (tail) ones, so we don't need to do + // any stores. For instance, if we fail on ld2, this means we had + // 2 or 3 bytes left to copy and we did not execute the ld8 nor ld4. + // + // This means that we are in a situation similar the a fault in the + // head part. That's nice! + // +failure_in1: +// sub ret0=enddst,dst1 // number of bytes to zero, i.e. not copied +// sub len=enddst,dst1,1 + sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied + sub len=endsrc,src1,1 + // + // we know that ret0 can never be zero at this point + // because we failed why trying to do a load, i.e. there is still + // some work to do. + // The failure_in1bis and length problem is taken care of at the + // calling side. + // + ;; +failure_in1bis: // from (failure_in3) + mov ar.lc=len // Continue with a stupid byte store. + ;; +5: + st1 [dst1]=r0,1 + br.cloop.dptk.few 5b + ;; +skip_loop: + mov pr=saved_pr,0xffffffffffff0000 + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs + br.ret.dptk.few rp + + // + // Here we simply restart the loop but instead + // of doing loads we fill the pipeline with zeroes + // We can't simply store r0 because we may have valid + // data in transit in the pipeline. + // ar.lc and ar.ec are setup correctly at this point + // + // we MUST use src1/endsrc here and not dst1/enddst because + // of the pipeline effect. + // +failure_in3: + sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied + ;; +2: +(p16) mov val1[0]=r0 +(p16) mov val2[0]=r0 +(EPI) st8 [dst1]=val1[PIPE_DEPTH-1],16 +(EPI) st8 [dst2]=val2[PIPE_DEPTH-1],16 + br.ctop.dptk.few 2b + ;; + cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? + sub len=enddst,dst1,1 // precompute len +(p6) br.cond.dptk.few failure_in1bis + ;; + mov pr=saved_pr,0xffffffffffff0000 + mov ar.lc=saved_lc + mov ar.pfs=saved_pfs + br.ret.dptk.few rp + + // + // handling of failures on stores: that's the easy part + // +failure_out: + sub ret0=enddst,dst1 + mov pr=saved_pr,0xffffffffffff0000 + mov ar.lc=saved_lc + + mov ar.pfs=saved_pfs + br.ret.dptk.few rp + + + .endp __copy_user - .endp __copy_user diff -u --recursive --new-file v2.3.47/linux/arch/mips/Makefile linux/arch/mips/Makefile --- v2.3.47/linux/arch/mips/Makefile Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/Makefile Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.13 1998/08/17 10:16:23 ralf Exp $ +# $Id: Makefile,v 1.22 2000/01/26 00:07:44 ralf Exp $ # # This file is subject to the terms and conditions of the GNU General Public # License. See the file "COPYING" in the main directory of this archive @@ -18,44 +18,27 @@ # ifdef CONFIG_CPU_LITTLE_ENDIAN tool-prefix = mipsel-linux- -ifdef CONFIG_MIPS_ECOFF -oformat = ecoff-littlemips -else -oformat = elf32-littlemips -endif else tool-prefix = mips-linux- -ifdef CONFIG_MIPS_ECOFF -oformat = ecoff-bigmips -else -oformat = elf32-bigmips -endif endif ifdef CONFIG_CROSSCOMPILE CROSS_COMPILE = $(tool-prefix) endif -LINKFLAGS = -static -N -MODFLAGS += -mlong-calls - # -# The new ELF GCC uses -G0 -mabicalls -fpic as default. We don't need PIC +# The ELF GCC uses -G0 -mabicalls -fpic as default. We don't need PIC # code in the kernel since it only slows down the whole thing. For the # old GCC these options are just the defaults. At some point we might # make use of global pointer optimizations. # # The DECStation requires an ECOFF kernel for remote booting, other MIPS -# machines may also. +# machines may also. Since BFD is incredibly buggy with respect to +# crossformat linking we rely on the elf2ecoff tool for format conversion. # -ifdef CONFIG_ELF_KERNEL -CFLAGS += -G 0 -mno-abicalls -fno-pic -LINKFLAGS += -G 0 -endif -ifdef CONFIG_ECOFF_KERNEL CFLAGS += -G 0 -mno-abicalls -fno-pic -LINKFLAGS += -G 0 -oformat ecoff-littlemips -endif +LINKFLAGS += -static -G 0 +MODFLAGS += -mlong-calls ifdef CONFIG_REMOTE_DEBUG CFLAGS := $(CFLAGS) -g @@ -125,7 +108,7 @@ LOADADDR += 0x80080000 endif -ifdef CONFIG_SGI +ifdef CONFIG_SGI_IP22 LIBS += arch/mips/sgi/kernel/sgikern.a arch/mips/arc/arclib.a SUBDIRS += arch/mips/sgi/kernel arch/mips/arc # @@ -134,7 +117,6 @@ # 8kb aligned or the handling of the current variable will break. # LOADADDR += 0x88002000 -HOSTCC = cc endif # @@ -146,6 +128,15 @@ endif # +# NEC DDB Vrc-5074 +# +ifdef CONFIG_DDB5074 +SUBDIRS += arch/mips/ddb5074 +LIBS += arch/mips/ddb5074/ddb5074.a +LOADADDR += 0x80080000 +endif + +# # Choosing incompatible machines durings configuration will result in # error messages during linking. Select a default linkscript if # none has been choosen above. @@ -171,7 +162,7 @@ HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o -SUBDIRS := $(SUBDIRS) $(addprefix arch/mips/, kernel mm lib tools) +SUBDIRS := $(addprefix arch/mips/, tools) $(SUBDIRS) $(addprefix arch/mips/, kernel mm lib) CORE_FILES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(CORE_FILES) LIBS := arch/mips/lib/lib.a $(LIBS) diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/Makefile linux/arch/mips/arc/Makefile --- v2.3.47/linux/arch/mips/arc/Makefile Mon Dec 20 18:48:21 1999 +++ linux/arch/mips/arc/Makefile Thu Feb 24 22:52:30 2000 @@ -1,4 +1,5 @@ -# $Id: Makefile,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ +# $Id: Makefile,v 1.2 2000/01/13 00:11:11 ralf Exp $ +# # Makefile for the SGI arcs prom monitor library routines # under Linux. # @@ -8,16 +9,8 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -OBJS = console.o init.o printf.o memory.o tree.o env.o \ - cmdline.o misc.o time.o file.o identify.o - -all: arclib.a - -arclib.a: $(OBJS) - $(AR) rcs arclib.a $(OBJS) - sync - -dep: - $(CPP) $(CPPFLAGS) -M *.c > .depend +L_TARGET = arclib.a +L_OBJS = console.o init.o printf.o memory.o tree.o env.o cmdline.o misc.o \ + time.o file.o identify.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/cmdline.c linux/arch/mips/arc/cmdline.c --- v2.3.47/linux/arch/mips/arc/cmdline.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/cmdline.c Thu Feb 24 22:52:30 2000 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: cmdline.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ + * $Id: cmdline.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/console.c linux/arch/mips/arc/console.c --- v2.3.47/linux/arch/mips/arc/console.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/console.c Thu Feb 24 22:52:30 2000 @@ -4,9 +4,8 @@ * Copyright (C) 1996 David S. Miller (dm@sgi.com) * Compability with board caches, Ulf Carlsson * - * $Id: console.c,v 1.2 1999/06/12 18:42:38 ulfc Exp $ + * $Id: console.c,v 1.3 1999/10/09 00:00:57 ralf Exp $ */ -#include #include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/env.c linux/arch/mips/arc/env.c --- v2.3.47/linux/arch/mips/arc/env.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/env.c Thu Feb 24 22:52:30 2000 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: env.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ + * $Id: env.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/file.c linux/arch/mips/arc/file.c --- v2.3.47/linux/arch/mips/arc/file.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/file.c Thu Feb 24 22:52:30 2000 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: file.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $ + * $Id: file.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/identify.c linux/arch/mips/arc/identify.c --- v2.3.47/linux/arch/mips/arc/identify.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/arc/identify.c Thu Feb 24 22:52:30 2000 @@ -7,14 +7,14 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: identify.c,v 1.2 1999/02/25 21:04:13 tsbogend Exp $ + * $Id: identify.c,v 1.3 1999/10/21 00:23:04 ralf Exp $ */ #include #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/init.c linux/arch/mips/arc/init.c --- v2.3.47/linux/arch/mips/arc/init.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/init.c Thu Feb 24 22:52:30 2000 @@ -1,9 +1,11 @@ -/* - * init.c: PROM library initialisation code. +/* $Id: init.c,v 1.4 1999/10/09 00:00:57 ralf Exp $ + * This file is subject to the terms and conditions of the GNU General Public+ + * License. See the file "COPYING" in the main directory of this archive + * for more details. * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * PROM library initialisation code. * - * $Id: init.c,v 1.2 1999/02/25 21:22:49 tsbogend Exp $ + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ #include #include @@ -11,7 +13,7 @@ #include -/* #define DEBUG_PROM_INIT */ +#undef DEBUG_PROM_INIT /* Master romvec interface. */ struct linux_romvec *romvec; @@ -43,18 +45,9 @@ prom_vers = pb->ver; prom_rev = pb->rev; prom_identify_arch(); -#ifdef CONFIG_SGI - printk("PROMLIB: SGI ARCS firmware Version %d Revision %d\n", - prom_vers, prom_rev); -#else printk("PROMLIB: ARC firmware Version %d Revision %d\n", prom_vers, prom_rev); -#endif prom_meminit(); - -#if 0 - prom_testtree(); -#endif #ifdef DEBUG_PROM_INIT { diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/memory.c linux/arch/mips/arc/memory.c --- v2.3.47/linux/arch/mips/arc/memory.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/memory.c Thu Feb 24 22:52:30 2000 @@ -4,25 +4,30 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: memory.c,v 1.5 1999/04/14 21:25:02 tsbogend Exp $ + * $Id: memory.c,v 1.10 2000/01/27 23:21:57 ralf Exp $ */ #include #include #include #include #include +#include #include +#include #include #include #include #include -/* #define DEBUG */ +#undef DEBUG -struct linux_mdesc * __init prom_getmdesc(struct linux_mdesc *curr) +extern char _end; + +struct linux_mdesc * __init +ArcGetMemoryDescriptor(struct linux_mdesc *Current) { - return romvec->get_mdesc(curr); + return romvec->get_mdesc(Current); } #ifdef DEBUG /* convenient for debugging */ @@ -50,159 +55,185 @@ #define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc] #endif -static struct prom_pmemblock prom_pblocks[PROM_MAX_PMEMBLOCKS]; - -struct prom_pmemblock * __init prom_getpblock_array(void) -{ - return &prom_pblocks[0]; -} +static struct prom_pmemblock pblocks[PROM_MAX_PMEMBLOCKS]; #define MEMTYPE_DONTUSE 0 #define MEMTYPE_PROM 1 #define MEMTYPE_FREE 2 -static int __init prom_memtype_classify (union linux_memtypes type) +static inline int memtype_classify_arcs (union linux_memtypes type) { - if (prom_flags & PROM_FLAG_ARCS) { switch (type.arcs) { - case arcs_free: - case arcs_fcontig: - return MEMTYPE_FREE; - case arcs_atmp: - case arcs_aperm: - return MEMTYPE_PROM; - default: - return MEMTYPE_DONTUSE; + case arcs_fcontig: + case arcs_free: + return MEMTYPE_FREE; + case arcs_atmp: + return MEMTYPE_PROM; + case arcs_eblock: + case arcs_rvpage: + case arcs_bmem: + case arcs_prog: + case arcs_aperm: + return MEMTYPE_DONTUSE; + default: + BUG(); } - } else { + while(1); /* Nuke warning. */ +} + +static inline int memtype_classify_arc (union linux_memtypes type) +{ switch (type.arc) { - case arc_free: - case arc_fcontig: - return MEMTYPE_FREE; - case arc_rvpage: - case arc_atmp: - case arc_aperm: - return MEMTYPE_PROM; - default: - return MEMTYPE_DONTUSE; + case arc_free: + case arc_fcontig: + return MEMTYPE_FREE; + case arc_atmp: + return MEMTYPE_PROM; + case arc_eblock: + case arc_rvpage: + case arc_bmem: + case arc_prog: + case arc_aperm: + return MEMTYPE_DONTUSE; + default: + BUG(); } - } + while(1); /* Nuke warning. */ } -static void __init prom_setup_memupper(void) +static int __init prom_memtype_classify (union linux_memtypes type) +{ + if (prom_flags & PROM_FLAG_ARCS) /* SGI is ``different'' ... */ + return memtype_classify_arcs(type); + + return memtype_classify_arc(type); +} + +static inline unsigned long find_max_low_pfn(void) { struct prom_pmemblock *p, *highest; + unsigned long pfn; - for(p = prom_getpblock_array(), highest = 0; p->size != 0; p++) { - if(p->base == 0xdeadbeef) - prom_printf("WHEEE, bogus pmemblock\n"); - if(!highest || p->base > highest->base) + p = pblocks; + highest = 0; + while (p->size != 0) { + if (!highest || p->base > highest->base) highest = p; + p++; } - mips_memory_upper = highest->base + highest->size; + + pfn = (highest->base + highest->size) >> PAGE_SHIFT; #ifdef DEBUG - prom_printf("prom_setup_memupper: mips_memory_upper = %08lx\n", - mips_memory_upper); + prom_printf("find_max_low_pfn: 0x%lx pfns.\n", pfn); #endif + return pfn; +} + +static inline struct prom_pmemblock *find_largest_memblock(void) +{ + struct prom_pmemblock *p, *largest; + + p = pblocks; + largest = 0; + while (p->size != 0) { + if (!largest || p->size > largest->size) + largest = p; + p++; + } + + return largest; } void __init prom_meminit(void) { + struct prom_pmemblock *largest; + unsigned long bootmap_size; struct linux_mdesc *p; int totram; int i = 0; - p = prom_getmdesc(PROM_NULL_MDESC); #ifdef DEBUG prom_printf("ARCS MEMORY DESCRIPTOR dump:\n"); + p = ArcGetMemoryDescriptor(PROM_NULL_MDESC); while(p) { prom_printf("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n", i, p, p->base, p->pages, mtypes(p->type)); - p = prom_getmdesc(p); + p = ArcGetMemoryDescriptor(p); i++; } #endif - p = prom_getmdesc(PROM_NULL_MDESC); + totram = 0; i = 0; - while(p) { - prom_pblocks[i].type = prom_memtype_classify (p->type); - prom_pblocks[i].base = ((p->base<pages << PAGE_SHIFT; - switch (prom_pblocks[i].type) { - case MEMTYPE_FREE: - totram += prom_pblocks[i].size; + p = PROM_NULL_MDESC; + while ((p = ArcGetMemoryDescriptor(p))) { + pblocks[i].type = prom_memtype_classify(p->type); + pblocks[i].base = p->base << PAGE_SHIFT; + pblocks[i].size = p->pages << PAGE_SHIFT; + + switch (pblocks[i].type) { + case MEMTYPE_FREE: + totram += pblocks[i].size; #ifdef DEBUG - prom_printf("free_chunk[%d]: base=%08lx size=%d\n", - i, prom_pblocks[i].base, - prom_pblocks[i].size); + prom_printf("free_chunk[%d]: base=%08lx size=%x\n", + i, pblocks[i].base, + pblocks[i].size); #endif - i++; - break; - case MEMTYPE_PROM: + i++; + break; + case MEMTYPE_PROM: #ifdef DEBUG - prom_printf("prom_chunk[%d]: base=%08lx size=%d\n", - i, prom_pblocks[i].base, - prom_pblocks[i].size); + prom_printf("prom_chunk[%d]: base=%08lx size=%x\n", + i, pblocks[i].base, + pblocks[i].size); #endif - i++; - break; - default: - break; - } - p = prom_getmdesc(p); - } - prom_pblocks[i].base = 0xdeadbeef; - prom_pblocks[i].size = 0; /* indicates last elem. of array */ - printk("PROMLIB: Total free ram %d bytes (%dK,%dMB)\n", - totram, (totram/1024), (totram/1024/1024)); + i++; + break; + default: + break; + } + } + pblocks[i].size = 0; - /* Setup upper physical memory bound. */ - prom_setup_memupper(); -} + max_low_pfn = find_max_low_pfn(); + largest = find_largest_memblock(); + bootmap_size = init_bootmem(largest->base >> PAGE_SHIFT, max_low_pfn); -/* Called from mem_init() to fixup the mem_map page settings. */ -void __init prom_fixup_mem_map(unsigned long start, unsigned long end) -{ - struct prom_pmemblock *p; - int i, nents; + for (i = 0; pblocks[i].size; i++) + if (pblocks[i].type == MEMTYPE_FREE) + free_bootmem(pblocks[i].base, pblocks[i].size); - /* Determine number of pblockarray entries. */ - p = prom_getpblock_array(); - for(i = 0; p[i].size; i++) - ; - nents = i; -restart: - while(start < end) { - for(i = 0; i < nents; i++) { - if((p[i].type == MEMTYPE_FREE) && - (start >= (p[i].base)) && - (start < (p[i].base + p[i].size))) { - start = p[i].base + p[i].size; - start &= PAGE_MASK; - goto restart; - } - } - set_bit(PG_reserved, &mem_map[MAP_NR(start)].flags); - start += PAGE_SIZE; + /* This test is simpleminded. It will fail if the bootmem bitmap + falls into multiple adjacent ARC memory areas. */ + if (bootmap_size > largest->size) { + prom_printf("CRITIAL: overwriting PROM data.\n"); + BUG(); } + reserve_bootmem(largest->base, bootmap_size); + + printk("PROMLIB: Total free ram %dK / %dMB.\n", + totram >> 10, totram >> 20); } -void prom_free_prom_memory (void) +void __init +prom_free_prom_memory (void) { - struct prom_pmemblock *p; - unsigned long addr; - unsigned long num_pages = 0; + struct prom_pmemblock *p; + unsigned long freed = 0; + unsigned long addr; - for(p = prom_getpblock_array(); p->size != 0; p++) { - if (p->type == MEMTYPE_PROM) { - for (addr = p->base; addr < p->base + p->size; addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - atomic_set(&mem_map[MAP_NR(addr)].count, 1); - free_page(addr); - num_pages++; - } + for (p = pblocks; p->size != 0; p++) { + if (p->type != MEMTYPE_PROM) + continue; + + addr = PAGE_OFFSET + p->base; + while (addr < p->base + p->size) { + ClearPageReserved(mem_map + MAP_NR(addr)); + set_page_count(mem_map + MAP_NR(addr), 1); + free_page(addr); + addr += PAGE_SIZE; + freed += PAGE_SIZE; + } } - } - printk ("Freeing prom memory: %dk freed\n",num_pages << (PAGE_SHIFT - 10)); + printk("Freeing prom memory: %ldkb freed\n", freed >> 10); } diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/misc.c linux/arch/mips/arc/misc.c --- v2.3.47/linux/arch/mips/arc/misc.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/misc.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $ +/* $Id: misc.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ * * misc.c: Miscellaneous ARCS PROM routines. * diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/printf.c linux/arch/mips/arc/printf.c --- v2.3.47/linux/arch/mips/arc/printf.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/printf.c Thu Feb 24 22:52:30 2000 @@ -4,9 +4,8 @@ * * Copyright (C) 1996 David S. Miller (dm@sgi.com) * - * $Id: printf.c,v 1.2 1999/06/12 18:42:38 ulfc Exp $ + * $Id: printf.c,v 1.3 1999/10/09 00:00:57 ralf Exp $ */ -#include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/salone.c linux/arch/mips/arc/salone.c --- v2.3.47/linux/arch/mips/arc/salone.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/salone.c Thu Feb 24 22:52:30 2000 @@ -4,7 +4,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: salone.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $ + * $Id: salone.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/time.c linux/arch/mips/arc/time.c --- v2.3.47/linux/arch/mips/arc/time.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/time.c Thu Feb 24 22:52:30 2000 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: time.c,v 1.1 1998/10/18 13:32:10 tsbogend Exp $ + * $Id: time.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/arc/tree.c linux/arch/mips/arc/tree.c --- v2.3.47/linux/arch/mips/arc/tree.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/arc/tree.c Thu Feb 24 22:52:30 2000 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: tree.c,v 1.1 1998/10/18 13:32:10 tsbogend Exp $ + * $Id: tree.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/Makefile linux/arch/mips/baget/Makefile --- v2.3.47/linux/arch/mips/baget/Makefile Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/baget/Makefile Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -# $Id$ +# $Id: Makefile,v 1.3 1999/08/13 17:07:26 harald Exp $ # # Makefile for the Baget specific kernel interface routines # under Linux. @@ -15,7 +15,7 @@ cp -f $< $@ O_TARGET := baget.a -O_OBJS := baget.o print.o setup.o time.o irq.o bagetIRQ.o reset.o wbflush.o +O_OBJS := baget.o print.o setup.o time.o irq.o bagetIRQ.o reset.o ifeq ($(CONFIG_SERIAL),y) OX_OBJS += vacserial.o diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/baget.c linux/arch/mips/baget/baget.c --- v2.3.47/linux/arch/mips/baget/baget.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/baget/baget.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id$ +/* $Id: baget.c,v 1.1 1999/01/17 03:49:37 ralf Exp $ * * baget.c: Baget low level stuff * diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/bagetIRQ.S linux/arch/mips/baget/bagetIRQ.S --- v2.3.47/linux/arch/mips/baget/bagetIRQ.S Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/baget/bagetIRQ.S Thu Feb 24 22:52:30 2000 @@ -1,11 +1,10 @@ -/* $Id$ +/* $Id: bagetIRQ.S,v 1.2 1999/08/18 23:37:42 ralf Exp $ * bagetIRQ.S: Interrupt exception dispatch code for Baget/MIPS * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov */ #include -#include #include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/balo.c linux/arch/mips/baget/balo.c --- v2.3.47/linux/arch/mips/baget/balo.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/baget/balo.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id$ +/* $Id: balo.c,v 1.1 1999/01/17 03:49:37 ralf Exp $ * * balo.c: BAget LOader * diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/balo_supp.S linux/arch/mips/baget/balo_supp.S --- v2.3.47/linux/arch/mips/baget/balo_supp.S Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/baget/balo_supp.S Thu Feb 24 22:52:30 2000 @@ -1,9 +1,10 @@ -/* $Id$ +/* $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 #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/irq.c linux/arch/mips/baget/irq.c --- v2.3.47/linux/arch/mips/baget/irq.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/baget/irq.c Thu Feb 24 22:52:30 2000 @@ -5,7 +5,7 @@ * Code (mostly sleleton and comments) derived from DECstation IRQ * handling. * - * $Id$ + * $Id: irq.c,v 1.6 2000/02/04 07:40:23 ralf Exp $ */ #include #include @@ -33,8 +33,6 @@ unsigned int local_irq_count[NR_CPUS]; unsigned long spurious_count = 0; -atomic_t __mips_bh_counter; - /* * This table is a correspondence between IRQ numbers and CPU PILs */ @@ -142,15 +140,6 @@ } /* - * Data definition for static irqaction allocation. - * It is used while SLAB module is not initialized. - */ - -#define MAX_STATIC_ALLOC 4 -struct irqaction static_irqaction[MAX_STATIC_ALLOC]; -int static_irq_count = 0; - -/* * Pointers to the low-level handlers: first the general ones, then the * fast ones, then the bad ones. */ @@ -193,7 +182,7 @@ int do_random, cpu; cpu = smp_processor_id(); - hardirq_enter(cpu); + irq_enter(cpu); kstat.irqs[cpu][irq]++; mask_irq(irq); @@ -215,7 +204,7 @@ printk("do_IRQ: Unregistered IRQ (0x%X) occured\n", irq); } unmask_irq(irq); - hardirq_exit(cpu); + irq_exit(cpu); /* unmasking and bottom half handling is done magically for us. */ } @@ -319,7 +308,7 @@ void *dev_id) { int retval; - struct irqaction * action = NULL; + struct irqaction * action; if (irq >= BAGET_IRQ_NR) return -EINVAL; @@ -328,22 +317,8 @@ if (irq_to_pil_map[irq] < 0) return -EINVAL; - if (irqflags & SA_STATIC_ALLOC) { - unsigned long flags; - - save_and_cli(flags); - if (static_irq_count < MAX_STATIC_ALLOC) - action = &static_irqaction[static_irq_count++]; - else - printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed " - "using kmalloc\n", irq, devname); - restore_flags(flags); - } - - if (action == NULL) - action = (struct irqaction *) + action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) return -ENOMEM; @@ -380,17 +355,6 @@ if (!irq[irq_action]) unmask_irq_count(irq); restore_flags(flags); - - if (action->flags & SA_STATIC_ALLOC) - { - /* This interrupt is marked as specially allocated - * so it is a bad idea to free it. - */ - printk("Attempt to free statically allocated " - "IRQ%d (%s)\n", irq, action->name); - return; - } - kfree(action); return; } @@ -422,6 +386,9 @@ *(volatile char*) BAGET_WRERR_ACK = 0; } +static struct irqaction irq0 = +{ write_err_interrupt, SA_INTERRUPT, 0, "bus write error", NULL, NULL}; + void __init init_IRQ(void) { irq_setup(); @@ -432,7 +399,6 @@ /* Enable interrupts for pils 2 and 3 (lines 0 and 1) */ modify_cp0_intmask(0, (1<<2)|(1<<3)); - if (request_irq(0/*fixme*/, write_err_interrupt, - SA_INTERRUPT|SA_STATIC_ALLOC, "write_err", NULL) < 0) + if (setup_baget_irq(0, &irq0) < 0) printk("init_IRQ: unable to register write_err irq\n"); } diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/print.c linux/arch/mips/baget/print.c --- v2.3.47/linux/arch/mips/baget/print.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/baget/print.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id$ +/* $Id: print.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ * * print.c: Simple print fascility * diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/prom/Makefile linux/arch/mips/baget/prom/Makefile --- v2.3.47/linux/arch/mips/baget/prom/Makefile Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/baget/prom/Makefile Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -# $Id$ +# $Id: Makefile,v 1.1 1999/01/17 03:49:40 ralf Exp $ # Makefile for the Baget/MIPS prom emulator library routines. # # Note! Dependencies are done automagically by 'make dep', which also diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/prom/init.c linux/arch/mips/baget/prom/init.c --- v2.3.47/linux/arch/mips/baget/prom/init.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/baget/prom/init.c Thu Feb 24 22:52:30 2000 @@ -3,9 +3,10 @@ * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov * - * $Id$ + * $Id: init.c,v 1.3 1999/10/09 00:00:57 ralf Exp $ */ #include +#include #include char arcs_cmdline[CL_SIZE]; @@ -17,4 +18,12 @@ mips_machtype = MACH_UNKNOWN; arcs_cmdline[0] = 0; return 0; +} + +void __init prom_fixup_mem_map(unsigned long start, unsigned long end) +{ +} + +void prom_free_prom_memory (void) +{ } diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/setup.c linux/arch/mips/baget/setup.c --- v2.3.47/linux/arch/mips/baget/setup.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/baget/setup.c Thu Feb 24 22:52:30 2000 @@ -1,10 +1,11 @@ -/* $Id$ +/* $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 #include #include @@ -16,8 +17,6 @@ extern long mips_memory_upper; -extern void wbflush_setup(void); - #define CACHEABLE_STR(val) ((val) ? "not cached" : "cached") #define MIN(a,b) (((a)<(b)) ? (a):(b)) @@ -480,8 +479,6 @@ printk("BT23/63-201n found.\n"); *BAGET_WRERR_ACK = 0; irq_setup = baget_irq_setup; - - wbflush_setup(); _machine_restart = baget_machine_restart; _machine_halt = baget_machine_halt; diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/time.c linux/arch/mips/baget/time.c --- v2.3.47/linux/arch/mips/baget/time.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/baget/time.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id$ +/* $Id: time.c,v 1.4 1999/10/09 00:00:57 ralf Exp $ * time.c: Baget/MIPS specific time handling details * * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov @@ -63,14 +63,14 @@ VIC_INT_LOW|VIC_INT_ENABLE, VIC_LINT2); } +static struct irqaction timer_irq = +{ timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; + void __init time_init(void) { - if (request_irq(BAGET_VIC_TIMER_IRQ, timer_interrupt, - SA_INTERRUPT|SA_STATIC_ALLOC, "timer", NULL) < 0) + if (setup_baget_irq(BAGET_VIC_TIMER_IRQ, &timer_irq) < 0) printk("time_init: unable request irq for system timer\n"); - timer_enable(); - /* We don't call sti() here, because it is too early for baget */ } diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/vacserial.c linux/arch/mips/baget/vacserial.c --- v2.3.47/linux/arch/mips/baget/vacserial.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/baget/vacserial.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id$ +/* $Id: vacserial.c,v 1.4 1999/10/09 00:00:57 ralf Exp $ * vacserial.c: VAC UART serial driver * This code stealed and adopted from linux/drivers/char/serial.c * See that for author info @@ -22,7 +22,8 @@ #define RS_STROBE_TIME (10*HZ) #define RS_ISR_PASS_LIMIT 2 /* Beget is not a super-computer (old=256) */ -#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) +#define IRQ_T(state) \ + ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) #define SERIAL_INLINE @@ -157,7 +158,7 @@ * memory if large numbers of serial ports are open. */ static unsigned char *tmp_buf; -static struct semaphore tmp_buf_sem = MUTEX; +static DECLARE_MUTEX(tmp_buf_sem); static inline int serial_paranoia_check(struct async_struct *info, kdev_t device, const char *routine) @@ -695,7 +696,7 @@ handler = rs_interrupt_single; - retval = request_irq(state->irq, handler, IRQ_T(info), + retval = request_irq(state->irq, handler, IRQ_T(state), "serial", NULL); if (retval) { if (capable(CAP_SYS_ADMIN)) { @@ -813,7 +814,7 @@ if (IRQ_ports[state->irq]) { free_irq(state->irq, NULL); retval = request_irq(state->irq, rs_interrupt_single, - IRQ_T(info), "serial", NULL); + IRQ_T(state), "serial", NULL); if (retval) printk("serial shutdown: request_irq: error %d" @@ -912,6 +913,8 @@ /* 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; if (baud == 38400 && ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) @@ -1357,7 +1360,7 @@ check_and_exit: if (!state->port || !state->type) return 0; - if (state->flags & ASYNC_INITIALIZED) { + if (info->flags & ASYNC_INITIALIZED) { if (((old_state.flags & ASYNC_SPD_MASK) != (state->flags & ASYNC_SPD_MASK)) || (old_state.custom_divisor != state->custom_divisor)) { @@ -1603,8 +1606,9 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) { struct async_struct *info = (struct async_struct *)tty->driver_data; - - if ( (tty->termios->c_cflag == old_termios->c_cflag) + 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; @@ -1613,7 +1617,7 @@ /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(cflag & CRTSCTS)) { tty->hw_stopped = 0; rs_start(tty); } @@ -1820,7 +1824,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, struct async_struct *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); struct serial_state *state = info->state; int retval; int do_clocal = 0, extra_count = 0; @@ -1960,6 +1964,9 @@ 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; diff -u --recursive --new-file v2.3.47/linux/arch/mips/baget/wbflush.c linux/arch/mips/baget/wbflush.c --- v2.3.47/linux/arch/mips/baget/wbflush.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/baget/wbflush.c Thu Feb 24 22:52:30 2000 @@ -4,8 +4,8 @@ * Copyright (C) 1999 Gleb Raiko & Vladimir Roganov */ +#include #include -#include void (*__wbflush) (void); diff -u --recursive --new-file v2.3.47/linux/arch/mips/boot/Makefile linux/arch/mips/boot/Makefile --- v2.3.47/linux/arch/mips/boot/Makefile Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/boot/Makefile Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.9 1999/04/07 18:45:23 harald Exp $ +# $Id: Makefile,v 1.10 1999/10/17 19:55:22 harald 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 @@ -46,6 +46,8 @@ clean: rm -f vmlinux.ecoff + rm -f addinitrd + rm -f elf2ecoff dummy: diff -u --recursive --new-file v2.3.47/linux/arch/mips/config.in linux/arch/mips/config.in --- v2.3.47/linux/arch/mips/config.in Wed Dec 8 14:11:25 1999 +++ linux/arch/mips/config.in Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.27 1999/06/17 13:25:44 ralf Exp $ +# $Id: config.in,v 1.42 2000/02/24 00:12:40 ralf Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -16,16 +16,18 @@ bool 'Support for Algorithmics P4032 (EXPERIMENTAL)' CONFIG_ALGOR_P4032 bool 'Support for BAGET MIPS series (EXPERIMENTAL)' CONFIG_BAGET_MIPS bool 'Support for DECstations (EXPERIMENTAL)' CONFIG_DECSTATION + bool 'Support for NEC DDB Vrc-5074 (EXPERIMENTAL)' CONFIG_DDB5074 fi bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000 bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700 -bool 'Support for SGI workstations' CONFIG_SGI +bool 'Support for SGI IP22' CONFIG_SGI_IP22 bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI # # Select some configuration options automatically for certain systems. # unset CONFIG_PCI +unset CONFIG_ISA unset CONFIG_MIPS_JAZZ unset CONFIG_VIDEO_G364 @@ -34,22 +36,44 @@ fi if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \ "$CONFIG_OLIVETTI_M700" = "y" ]; then + define_bool CONFIG_ISA y + define_bool CONFIG_HAVE_IO_PORTS y define_bool CONFIG_MIPS_JAZZ y define_bool CONFIG_FB y define_bool CONFIG_FB_G364 y fi if [ "$CONFIG_ACER_PICA_61" = "y" ]; then + define_bool CONFIG_ISA y + define_bool CONFIG_HAVE_IO_PORTS y define_bool CONFIG_MIPS_JAZZ y fi if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then + define_bool CONFIG_ISA y + define_bool CONFIG_HAVE_IO_PORTS y define_bool CONFIG_PCI y fi +if [ "$CONFIG_DDB5074" = "y" ]; then + define_bool CONFIG_PCI y + define_bool CONFIG_HAVE_IO_PORTS y +fi endmenu mainmenu_option next_comment comment 'CPU selection' -choice 'CPU type' \ +if [ "$CONFIG_CPU_ADVANCED" = "y" ]; then + choice 'CPU core' \ + "R3000 CONFIG_CPU_R3000 \ + R4300 CONFIG_CPU_R4300 \ + R4x00 CONFIG_CPU_R4X00 \ + R5000 CONFIG_CPU_R5000 \ + R56x0 CONFIG_CPU_NEVADA \ + R10000 CONFIG_CPU_R10000" R4x00 + + bool ' ll/sc Instructions available' CONFIG_CPU_HAS_LLSC + bool ' Writeback Buffer available' CONFIG_CPU_HAS_WB +else + choice 'CPU type' \ "R3000 CONFIG_CPU_R3000 \ R6000 CONFIG_CPU_R6000 \ R4300 CONFIG_CPU_R4300 \ @@ -57,13 +81,28 @@ R5000 CONFIG_CPU_R5000 \ R56x0 CONFIG_CPU_NEVADA \ R8000 CONFIG_CPU_R8000 \ - R10000 CONFIG_CPU_R10000" R4x00 + R10000 CONFIG_CPU_R10000 \ + Advanced CONFIG_CPU_ADVANCED" R4x00 + + if [ "$CONFIG_CPU_R3000" = "y" ]; then + if [ "$CONFIG_DECSTATION" = "y" ]; then + define_bool CONFIG_CPU_HAS_LLSC n + define_bool CONFIG_CPU_HAS_WB y + else + define_bool CONFIG_CPU_HAS_LLSC n + define_bool CONFIG_CPU_HAS_WB n + fi + else + define_bool CONFIG_CPU_HAS_LLSC y + define_bool CONFIG_CPU_HAS_WB n + fi +fi endmenu mainmenu_option next_comment comment 'General setup' -if [ "$CONFIG_DECSTATION" = "y" ]; then +if [ "$CONFIG_DECSTATION" = "y" -o "$CONFIG_DDB5074" = "y" ]; then define_bool CONFIG_CPU_LITTLE_ENDIAN y else bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN @@ -83,11 +122,15 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Networking support' CONFIG_NET + +source drivers/pci/Config.in +source drivers/pcmcia/Config.in + bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL -if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then +if [ "$CONFIG_SGI_IP22" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then source drivers/parport/Config.in fi endmenu @@ -114,8 +157,6 @@ endmenu fi -source drivers/i2o/Config.in - source drivers/pnp/Config.in source drivers/block/Config.in @@ -180,7 +221,8 @@ comment ' CCP compressors for PPP are only built as modules.' fi if [ "$CONFIG_SGI" = "y" ]; then - bool ' SGI Seeq ethernet controller support' CONFIG_SGISEEQ + bool ' SGI Seeq ethernet controller support' CONFIG_SGISEEQ + fi fi if [ "$CONFIG_DECSTATION" = "y" ]; then bool ' DEC LANCE ethernet controller support' CONFIG_DECLANCE @@ -208,7 +250,6 @@ fi endmenu - mainmenu_option next_comment comment 'Old CD-ROM drivers (not SCSI, not IDE)' @@ -227,18 +268,18 @@ bool 'Virtual terminal' CONFIG_VT if [ "$CONFIG_VT" = "y" ]; then - bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE + bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE fi - if [ "$CONFIG_SGI" = "y" ]; then + tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL + if [ "$CONFIG_SGI_IP22" = "y" ]; then bool 'SGI PROM Console Support' CONFIG_SGI_PROM_CONSOLE fi - tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL if [ "$CONFIG_SERIAL" = "y" ]; then - bool ' DZ11 Serial Support' CONFIG_DZ + bool 'DZ11 Serial Support' CONFIG_DZ if [ "$CONFIG_TC" = "y" ]; then - bool ' Z85C30 Serial Support' CONFIG_ZS + bool 'Z85C30 Serial Support' CONFIG_ZS fi - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE fi bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then @@ -246,29 +287,33 @@ fi bool 'Keyboard Support' CONFIG_KEYBOARD bool 'Mouse Support' CONFIG_MOUSE -# bool 'Enhanced Real Time Clock Support' CONFIG_RTC +# bool 'Enhanced Real Time Clock Support' CONFIG_RTC endmenu fi source drivers/usb/Config.in +source drivers/misc/Config.in + source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then mainmenu_option next_comment comment 'Console drivers' - if [ "$CONFIG_SGI" = "y" ]; then + if [ "$CONFIG_SGI_IP22" = "y" ]; then tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then - define_bool CONFIG_DUMMY_CONSOLE y + define_bool CONFIG_DUMMY_CONSOLE y + else + define_bool CONFIG_FONT_8x16 y fi else if [ "$CONFIG_DECSTATION" != "y" ]; then bool 'VGA text console' CONFIG_VGA_CONSOLE fi - bool 'Support for frame buffer devices' CONFIG_FB + bool 'Support for frame buffer devices' CONFIG_FB source drivers/video/Config.in - fi + fi endmenu fi @@ -283,7 +328,7 @@ endmenu fi -if [ "$CONFIG_SGI" = "y" ]; then +if [ "$CONFIG_SGI_IP22" = "y" ]; then source drivers/sgi/Config.in fi @@ -296,7 +341,7 @@ bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE fi if [ "$CONFIG_SERIAL" = "y" ]; then - bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG + bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -u --recursive --new-file v2.3.47/linux/arch/mips/ddb5074/Makefile linux/arch/mips/ddb5074/Makefile --- v2.3.47/linux/arch/mips/ddb5074/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5074/Makefile Thu Feb 24 22:52:30 2000 @@ -0,0 +1,22 @@ +# +# 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... +# +# $Id: Makefile,v 1.1 2000/01/26 00:07:44 ralf Exp $ +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET = ddb5074.a +O_OBJS = setup.o irq.o time.o prom.o pci.o int-handler.o nile4.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/arch/mips/ddb5074/int-handler.S linux/arch/mips/ddb5074/int-handler.S --- v2.3.47/linux/arch/mips/ddb5074/int-handler.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5074/int-handler.S Thu Feb 24 22:52:30 2000 @@ -0,0 +1,124 @@ +/* + * 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 Suprastructure Center Europe (SUPC-E), Brussels + * + * $Id: int-handler.S,v 1.2 2000/01/27 02:06:56 ralf Exp $ + */ + +#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 s0, CP0_CAUSE # get irq mask + +#if 1 + mfc0 t2,CP0_STATUS # get enabled interrupts + and s0,t2 # isolate allowed ones +#endif + /* First we check for r4k counter/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: + j ret_from_irq + nop + END(ddbIRQ) diff -u --recursive --new-file v2.3.47/linux/arch/mips/ddb5074/irq.c linux/arch/mips/ddb5074/irq.c --- v2.3.47/linux/arch/mips/ddb5074/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5074/irq.c Thu Feb 24 22:52:30 2000 @@ -0,0 +1,230 @@ +/* + * arch/mips/ddb5074/irq.c -- NEC DDB Vrc-5074 interrupt routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Suprastructure Center Europe (SUPC-E), Brussels + * + * $Id: irq.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ + */ + +#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); + + +static 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 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-5074 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 + * IRQ12 - mouse + */ + + /* + * 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 */ + nile4_enable_irq(NILE4_INT_INTE); + + request_region(M1543_PNP_CONFIG, 2, "M1543 config"); + request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR"); +} + +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); + nile4_set_pci_irq_level_or_edge(4, 1); + + /* PCI INTA#-D# must be active low, INTE# must be active high */ + nile4_set_pci_irq_polarity(0, 0); + nile4_set_pci_irq_polarity(1, 0); + nile4_set_pci_irq_polarity(2, 0); + nile4_set_pci_irq_polarity(3, 0); + nile4_set_pci_irq_polarity(4, 1); + + for (i = 0; i < 16; i++) + nile4_clear_irq(i); + + /* Enable CPU int #0 */ + nile4_enable_irq_output(0); + + request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4"); +} + + +/* + * 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 1 + volatile static int nesting = 0; + if (nesting++ == 0) + ddb5074_led_d3(1); + ddb5074_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<>= 1) + if (mask & 1) { + nile4_disable_irq(nile4_irq); + if (nile4_irq == NILE4_INT_INTE) { + 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 1 + if (--nesting == 0) + ddb5074_led_d3(0); + ddb5074_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 __init ddb_irq_setup(void) +{ +#ifdef CONFIG_REMOTE_DEBUG + if (remote_debug) + set_debug_traps(); + breakpoint(); /* you may move this line to whereever you want :-) */ +#endif + request_region(0x20, 0x20, "pic1"); + request_region(0xa0, 0x20, "pic2"); + i8259_setup_irq(2, &irq2); + + nile4_irq_setup(); + m1543_irq_setup(); + + set_except_vector(0, ddbIRQ); +} + diff -u --recursive --new-file v2.3.47/linux/arch/mips/ddb5074/nile4.c linux/arch/mips/ddb5074/nile4.c --- v2.3.47/linux/arch/mips/ddb5074/nile4.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5074/nile4.c Thu Feb 24 22:52:30 2000 @@ -0,0 +1,294 @@ +/* + * arch/mips/ddb5074/nile4.c -- NEC Vrc-5074 Nile 4 support routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Suprastructure Center Europe (SUPC-E), Brussels + * + * $Id: nile4.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ + */ + +#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. + */ + (void)nile4_in32(pdar); + (void)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 -u --recursive --new-file v2.3.47/linux/arch/mips/ddb5074/pci.c linux/arch/mips/ddb5074/pci.c --- v2.3.47/linux/arch/mips/ddb5074/pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5074/pci.c Thu Feb 24 22:52:30 2000 @@ -0,0 +1,357 @@ +/* + * arch/mips/ddb5074/pci.c -- NEC DDB Vrc-5074 PCI access routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Albert Dorofeev + * Sony Suprastructure Center Europe (SUPC-E), Brussels + * + * $Id: pci.c,v 1.4 2000/02/18 00:02:17 ralf Exp $ + */ + +#include +#include +#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; + + /* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0, 0); + if (slot_num > 2) + pci_addr = 0x00040000 << slot_num; + else + virt_addr += 0x00040000 << 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 8000000 - 64 bit - 128 MB (PCI IO space) */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 64, + 1, 1); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); +} + + +static int nile4_pci_read_config_dword( struct pci_dev *dev, + int where, u32 *val) +{ + int slot_num, func_num; + u32 base; + + /* + * For starters let's do configuration cycle 0 only (one bus only) + */ + if (dev->bus->number) + return PCIBIOS_FUNC_NOT_SUPPORTED; + + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + if (slot_num == 5) { + /* + * This is Nile 4 and it will crash if we access it like other + * devices + */ + *val = nile4_in32(NILE4_PCI_BASE + where); + return PCIBIOS_SUCCESSFUL; + } + base = nile4_pre_pci_access0(slot_num); + *val = *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc))); + 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; + + /* + * For starters let's do configuration cycle 0 only (one bus only) + */ + if (dev->bus->number) + return PCIBIOS_FUNC_NOT_SUPPORTED; + + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + if (slot_num == 5) { + /* + * This is Nile 4 and it will crash if we access it like other + * devices + */ + nile4_out32(NILE4_PCI_BASE + where, val); + return PCIBIOS_SUCCESSFUL; + } + base = nile4_pre_pci_access0(slot_num); + *((volatile u32 *)(base + (func_num << 8) + (where & 0xfc))) = 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, &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, &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, &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, 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, &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, 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 +}; + + +static void __init pcibios_claim_resources(struct list_head *bus_list) +{ + struct list_head *ln, *dn; + struct pci_bus *bus; + struct pci_dev *dev; + int idx; + + for (ln = bus_list->next; ln != bus_list; ln = ln->next) { + bus = pci_bus_b(ln); + for (dn = bus->devices.next; dn != &bus->devices; dn = dn->next) { + dev = pci_dev_b(dn); + for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) { + struct resource *r = &dev->resource[idx]; + struct resource *pr; + if (!r->start) + continue; + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) { + printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); + /* We probably should disable the region, shouldn't we? */ + } + } + } + pcibios_claim_resources(&bus->children); + } +} + + +void pcibios_init(void) +{ + printk("PCI: Probing PCI hardware\n"); + ioport_resource.end = 0x1ffffff; + pci_scan_bus(0, &nile4_pci_ops, NULL); + pcibios_claim_resources(&pci_root_buses); +} + +void pcibios_fixup_bus(struct pci_bus *bus) +{ + struct list_head *dn; + struct pci_dev *dev; + extern struct pci_dev *pci_pmu; /* for LEDs D2 and D3 */ + int slot_num, func_num; + u8 t8; + + /* + * FIXME: PMON doesn't autoconfigure the PCI devices + * For now we just hardcode them for our configuration + */ + printk("PCI: Configuring PCI devices (hardcoded)\n"); + for (dn = bus->devices.next; dn != &bus->devices; dn = dn->next) { + dev = pci_dev_b(dn); + + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + printk(" Device %2d: ", slot_num); + switch (slot_num) { + case 0: + printk("[onboard] Acer Labs M1533 Aladdin IV\n"); + dev->irq = nile4_to_irq(NILE4_INT_INTE); + break; + case 1: + printk("[onboard] DEC DC21140\n"); + dev->irq = nile4_to_irq(NILE4_INT_INTA); + dev->resource[0].start = 0x100000; + dev->resource[0].end = dev->resource[0].start+0x7f; + nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + dev->resource[0].start); + dev->resource[1].start = 0x1000000; + dev->resource[1].end = dev->resource[1].start+0x7f; + nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + dev->resource[1].start); + break; + case 2: + printk("[slot 1] Realtek 8029\n"); + dev->irq = nile4_to_irq(NILE4_INT_INTA); + dev->resource[0].start = 0x800000; + dev->resource[0].end = dev->resource[0].start+0x1f; + nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + dev->resource[0].start); + break; + case 3: + printk("[slot 2] DEC DC21140 (#2)\n"); + dev->irq = nile4_to_irq(NILE4_INT_INTB); + dev->resource[0].start = 0x1000000; + dev->resource[0].end = dev->resource[0].start+0x7f; + nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + dev->resource[0].start); + dev->resource[1].start = 0x4000000; + dev->resource[1].end = dev->resource[1].start+0x7f; + nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + dev->resource[1].start); + break; + case 4: + printk("[slot 3] Promise Technology IDE UltraDMA/33"); + printk(" or 3Com 3c905 :-)\n"); + dev->irq = nile4_to_irq(NILE4_INT_INTC); + dev->resource[0].start = 0x1800000; + dev->resource[0].end = dev->resource[0].start+0x7fffff; + nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + dev->resource[0].start); + break; + case 5: + printk("[onboard] NEC Vrc-5074 Nile 4 Host Bridge\n"); + /* + * Fixup so the serial driver can use the UART + */ + dev->irq = nile4_to_irq(NILE4_INT_UART); + dev->resource[0].start = PHYSADDR(NILE4_BASE); + dev->resource[0].end = dev->resource[0].start+NILE4_SIZE-1; + dev->resource[0].flags = IORESOURCE_MEM | + PCI_BASE_ADDRESS_MEM_TYPE_64; + + break; + case 10: + printk("[onboard] Acer Labs M7101 PMU\n"); + pci_pmu = dev; + /* 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); + break; + case 13: + printk("[onboard] Acer Labs M5237 USB\n"); + dev->irq = nile4_to_irq(NILE4_INT_INTE); + dev->resource[0].start = 0x1001000; + dev->resource[0].end = dev->resource[0].start+0xfff; + nile4_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, + dev->resource[0].start); + break; + default: + printk("\n"); + break; + } + } +} + +char *pcibios_setup (char *str) +{ + 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_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) +{ + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; +} + +int __init pcibios_enable_device(struct pci_dev *dev) +{ + printk("pcibios_enable_device for %04x:%04x\n", dev->vendor, dev->device); + panic("pcibios_enable_device: not yet implemented\n"); +} + +void __init pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{} + +struct pci_fixup pcibios_fixups[] = {}; + diff -u --recursive --new-file v2.3.47/linux/arch/mips/ddb5074/prom.c linux/arch/mips/ddb5074/prom.c --- v2.3.47/linux/arch/mips/ddb5074/prom.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5074/prom.c Thu Feb 24 22:52:30 2000 @@ -0,0 +1,62 @@ +/* + * arch/mips/ddb5074/prom.c -- NEC DDB Vrc-5074 PROM routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Suprastructure Center Europe (SUPC-E), Brussels + * + * $Id: prom.c,v 1.2 2000/02/14 17:07:36 ralf Exp $ + */ + +#include +#include +#include +#include +#include +#include + + +char arcs_cmdline[CL_SIZE]; + +extern char _end; + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) + + +void __init prom_init(const char *s) +{ + int i = 0; + unsigned long mem_size, free_start, free_end, start_pfn, bootmap_size; + +// _serinit(); + + if (s != (void *)-1) + while (*s && i < sizeof(arcs_cmdline)-1) + arcs_cmdline[i++] = *s++; + arcs_cmdline[i] = '\0'; + + mips_machgroup = MACH_GROUP_NEC_DDB; + mips_machtype = MACH_NEC_DDB5074; + /* 64 MB non-upgradable */ + mem_size = 64 << 20; + + free_start = PHYSADDR(PFN_ALIGN(&_end)); + free_end = mem_size; + start_pfn = PFN_UP((unsigned long)&_end); + + /* Register all the contiguous memory with the bootmem allocator + and free it. Be careful about the bootmem freemap. */ + bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT); + + /* Free the entire available memory after the _end symbol. */ + free_start += bootmap_size; + free_bootmem(free_start, free_end-free_start); +} + +void __init prom_fixup_mem_map(unsigned long start, unsigned long end) +{ +} + +void __init prom_free_prom_memory(void) +{ +} diff -u --recursive --new-file v2.3.47/linux/arch/mips/ddb5074/setup.c linux/arch/mips/ddb5074/setup.c --- v2.3.47/linux/arch/mips/ddb5074/setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5074/setup.c Thu Feb 24 22:52:30 2000 @@ -0,0 +1,244 @@ +/* + * arch/mips/ddb5074/setup.c -- NEC DDB Vrc-5074 setup routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Suprastructure Center Europe (SUPC-E), Brussels + * + * $Id: setup.c,v 1.2 2000/02/14 17:07:36 ralf Exp $ + */ + +#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 rtc_ops ddb_rtc_ops; + +static void ddb_machine_restart(char *command) +{ + u32 t; + + // FIXME: This doesn't seem to work... + printk("Restarting DDB Vrc-5074..."); + /* 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); + printk("Restart failed!\n"); + do {} while (1); +} + +static void ddb_machine_halt(void) +{ + printk("DDB Vrc-5074 halted.\n"); + do {} while (1); +} + +static void ddb_machine_power_off(void) +{ + printk("DDB Vrc-5074 halted. Please turn off the power.\n"); + do {} while (1); +} + +extern void ddb_irq_setup(void); + +void (*board_time_init)(struct irqaction *irq); + + +static void __init ddb_time_init(struct irqaction *irq) +{ + /* set the clock to 1 Hz */ + nile4_out32(NILE4_T2CTRL, 1000000); + /* 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); + set_cp0_status(ST0_IM, IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); +} + +void __init ddb_setup(void) +{ + irq_setup = ddb_irq_setup; + mips_io_port_base = NILE4_PCI_IO_BASE; + isa_slot_offset = NILE4_PCI_MEM_BASE; + request_region(0x00, 0x20, "dma1"); + request_region(0x40, 0x20, "timer"); + request_region(0x70, 0x10, "rtc"); + request_region(0x80, 0x10, "dma page reg"); + request_region(0xc0, 0x20, "dma2"); + board_time_init = ddb_time_init; + + _machine_restart = ddb_machine_restart; + _machine_halt = ddb_machine_halt; + _machine_power_off = ddb_machine_power_off; + + rtc_ops = &ddb_rtc_ops; +} + +int __init page_is_ram(unsigned long pagenr) +{ + return 1; +} + + +#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 ddb5074_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 ddb5074_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 ddb5074_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 -u --recursive --new-file v2.3.47/linux/arch/mips/ddb5074/time.c linux/arch/mips/ddb5074/time.c --- v2.3.47/linux/arch/mips/ddb5074/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/ddb5074/time.c Thu Feb 24 22:52:30 2000 @@ -0,0 +1,35 @@ +/* + * arch.mips/ddb5074/time.c -- Timer routines + * + * Copyright (C) 2000 Geert Uytterhoeven + * Sony Suprastructure Center Europe (SUPC-E), Brussels + * + * $Id* + */ + +#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 -u --recursive --new-file v2.3.47/linux/arch/mips/dec/Makefile linux/arch/mips/dec/Makefile --- v2.3.47/linux/arch/mips/dec/Makefile Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/dec/Makefile Thu Feb 24 22:52:30 2000 @@ -13,7 +13,7 @@ all: dec.o O_TARGET := dec.o -O_OBJS := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o wbflush.o +O_OBJS := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o ifdef CONFIG_PROM_CONSOLE O_OBJS += promcon.o @@ -21,6 +21,12 @@ ifdef CONFIG_SERIAL O_OBJS += serial.o +endif + +ifeq ($(CONFIG_MODULES),y) + OX_OBJS = wbflush.o +else + O_OBJS += wbflush.o endif int-handler.o: int-handler.S diff -u --recursive --new-file v2.3.47/linux/arch/mips/dec/irq.c linux/arch/mips/dec/irq.c --- v2.3.47/linux/arch/mips/dec/irq.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/dec/irq.c Thu Feb 24 22:52:30 2000 @@ -4,7 +4,7 @@ * Copyright (C) 1992 Linus Torvalds * Copyright (C) 1994, 1995, 1996, 1997 Ralf Baechle * - * $Id: irq.c,v 1.3 1999/04/11 17:06:16 harald Exp $ + * $Id: irq.c,v 1.6 2000/02/04 07:40:23 ralf Exp $ */ #include #include @@ -114,8 +114,6 @@ 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 @@ -129,7 +127,7 @@ int do_random, cpu; cpu = smp_processor_id(); - hardirq_enter(cpu); + irq_enter(cpu); kstat.irqs[cpu][irq]++; mask_irq(irq); @@ -149,7 +147,7 @@ unmask_irq(irq); __cli(); } - hardirq_exit(cpu); + irq_exit(cpu); /* unmasking and bottom half handling is done magically for us. */ } diff -u --recursive --new-file v2.3.47/linux/arch/mips/dec/prom/Makefile linux/arch/mips/dec/prom/Makefile --- v2.3.47/linux/arch/mips/dec/prom/Makefile Mon Dec 20 18:48:21 1999 +++ linux/arch/mips/dec/prom/Makefile Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -# $Id: $ +# $Id: Makefile,v 1.2 2000/02/05 06:47:08 ralf Exp $ # Makefile for the DECstation prom monitor library routines # under Linux. # diff -u --recursive --new-file v2.3.47/linux/arch/mips/dec/prom/cmdline.c linux/arch/mips/dec/prom/cmdline.c --- v2.3.47/linux/arch/mips/dec/prom/cmdline.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/dec/prom/cmdline.c Thu Feb 24 22:52:30 2000 @@ -3,10 +3,11 @@ * * Copyright (C) 1998 Harald Koerfgen * - * $Id: $ + * $Id: cmdline.c,v 1.2 1999/10/09 00:00:57 ralf Exp $ */ #include #include +#include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/dec/prom/identify.c linux/arch/mips/dec/prom/identify.c --- v2.3.47/linux/arch/mips/dec/prom/identify.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/dec/prom/identify.c Thu Feb 24 22:52:30 2000 @@ -3,9 +3,10 @@ * * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine * - * $Id: $ + * $Id: identify.c,v 1.2 1999/10/09 00:00:58 ralf Exp $ */ #include +#include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/dec/prom/init.c linux/arch/mips/dec/prom/init.c --- v2.3.47/linux/arch/mips/dec/prom/init.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/dec/prom/init.c Thu Feb 24 22:52:30 2000 @@ -3,9 +3,11 @@ * * Copyright (C) 1998 Harald Koerfgen * - * $Id: $ + * $Id: init.c,v 1.4 1999/10/09 00:00:58 ralf Exp $ */ #include +#include +#include #include "prom.h" /* @@ -81,11 +83,30 @@ int __init prom_init(int argc, char **argv, unsigned long magic, int *prom_vec) { + extern void dec_machine_halt(void); + /* Determine which PROM's we have (and therefore which machine we're on!) */ which_prom(magic, prom_vec); if (magic == REX_PROM_MAGIC) rex_clear_cache(); + + /* Were we compiled with the right CPU option? */ +#if defined(CONFIG_CPU_R3000) + if ((mips_cputype == CPU_R4000SC) || (mips_cputype == CPU_R4400SC)) { + prom_printf("Sorry, this kernel is compiled for the wrong CPU type!\n"); + prom_printf("Please recompile with \"CONFIG_CPU_R4x00 = y\"\n"); + dec_machine_halt(); + } +#endif + +#if defined(CONFIG_CPU_R4x00) + if ((mips_cputype == CPU_R3000) || (mips_cputype == CPU_R3000A)) { + prom_printf("Sorry, this kernel is compiled for the wrong CPU type!\n"); + prom_printf("Please recompile with \"CONFIG_CPU_R3000 = y\"\n"); + dec_machine_halt(); + } +#endif prom_meminit(magic); prom_identify_arch(magic); diff -u --recursive --new-file v2.3.47/linux/arch/mips/dec/prom/memory.c linux/arch/mips/dec/prom/memory.c --- v2.3.47/linux/arch/mips/dec/prom/memory.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/dec/prom/memory.c Thu Feb 24 22:52:30 2000 @@ -3,11 +3,19 @@ * * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine * - * $Id: $ + * $Id: memory.c,v 1.4 2000/02/13 20:52:05 harald Exp $ */ -#include #include -#include +#include +#include +#include +#include + +#include +#include + +#include + #include "prom.h" typedef struct { @@ -23,10 +31,13 @@ extern int (*prom_printf)(char *, ...); #endif -extern unsigned long mips_memory_upper; - volatile unsigned long mem_err = 0; /* So we know an error occured */ +extern char _end; + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) + /* * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen * off the end of real memory. Only suitable for the 2100/3100's (PMAX). @@ -78,26 +89,72 @@ if (bm->bitmap[i] == 0xff) mem_size += (8 * bm->pagesize); } + return (mem_size); } void __init prom_meminit(unsigned int magic) { + unsigned long free_start, free_end, start_pfn, bootmap_size; + unsigned long mem_size = 0; + if (magic != REX_PROM_MAGIC) - mips_memory_upper = KSEG0 + pmax_get_memory_size(); + mem_size = pmax_get_memory_size(); else - mips_memory_upper = KSEG0 + rex_get_memory_size(); + mem_size = rex_get_memory_size(); + + free_start = PHYSADDR(PFN_ALIGN(&_end)); + free_end = mem_size; + start_pfn = PFN_UP((unsigned long)&_end); #ifdef PROM_DEBUG - prom_printf("mips_memory_upper: 0x%08x\n", mips_memory_upper); + prom_printf("free_start: 0x%08x\n", free_start); + prom_printf("free_end: 0x%08x\n", free_end); + prom_printf("start_pfn: 0x%08x\n", start_pfn); #endif + + /* Register all the contiguous memory with the bootmem allocator + and free it. Be careful about the bootmem freemap. */ + bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT); + free_bootmem(free_start + bootmap_size, free_end - free_start - bootmap_size); } -/* Called from mem_init() to fixup the mem_map page settings. */ -void __init prom_fixup_mem_map(unsigned long start, unsigned long end) +int __init page_is_ram(unsigned long pagenr) { + return 1; } void prom_free_prom_memory (void) { + unsigned long addr, end; + extern char _ftext; + + /* + * Free everything below the kernel itself but leave + * the first page reserved for the exception handlers. + */ + +#ifdef CONFIG_DECLANCE + /* + * Leave 128 KB reserved for Lance memory for + * IOASIC DECstations. + * + * XXX: save this address for use in dec_lance.c? + */ + if (IOASIC) + end = PHYSADDR(&_ftext) - 0x00020000; + else +#endif + end = PHYSADDR(&_ftext); + + addr = PAGE_SIZE; + while (addr < end) { + ClearPageReserved(mem_map + MAP_NR(addr)); + set_page_count(mem_map + MAP_NR(addr), 1); + free_page(addr); + addr += PAGE_SIZE; + } + + printk("Freeing unused PROM memory: %dk freed\n", + (end - PAGE_SIZE) >> 10); } diff -u --recursive --new-file v2.3.47/linux/arch/mips/dec/rtc-dec.c linux/arch/mips/dec/rtc-dec.c --- v2.3.47/linux/arch/mips/dec/rtc-dec.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/dec/rtc-dec.c Thu Feb 24 22:52:30 2000 @@ -1,5 +1,5 @@ -/* $Id: rtc-jazz.c,v 1.2 1998/06/25 20:19:14 ralf Exp $ +/* $Id: rtc-dec.c,v 1.1 1999/01/17 03:49:42 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 diff -u --recursive --new-file v2.3.47/linux/arch/mips/dec/wbflush.c linux/arch/mips/dec/wbflush.c --- v2.3.47/linux/arch/mips/dec/wbflush.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/dec/wbflush.c Thu Feb 24 22:52:30 2000 @@ -102,3 +102,9 @@ static void wbflush_kn03(void) { } + +#ifdef EXPORT_SYMTAB +#include + +EXPORT_SYMBOL(__wbflush); +#endif diff -u --recursive --new-file v2.3.47/linux/arch/mips/defconfig linux/arch/mips/defconfig --- v2.3.47/linux/arch/mips/defconfig Wed Dec 8 14:11:25 1999 +++ linux/arch/mips/defconfig Thu Feb 24 22:52:30 2000 @@ -5,18 +5,20 @@ # # Code maturity level options # -# CONFIG_EXPERIMENTAL is not set +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_DECSTATION is not set +# CONFIG_DDB5074 is not set # CONFIG_MIPS_MAGNUM_4000 is not set # CONFIG_OLIVETTI_M700 is not set -# CONFIG_SGI is not set -CONFIG_SNI_RM200_PCI=y -CONFIG_PCI=y -CONFIG_PCI_NAMES=y +CONFIG_SGI_IP22=y +# CONFIG_SNI_RM200_PCI is not set # # CPU selection @@ -24,77 +26,68 @@ # CONFIG_CPU_R3000 is not set # CONFIG_CPU_R6000 is not set # CONFIG_CPU_R4300 is not set -CONFIG_CPU_R4X00=y -# CONFIG_CPU_R5000 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_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=y +# CONFIG_CPU_HAS_WB is not set # # General setup # -CONFIG_PCI_QUIRKS=y -CONFIG_PCI_OLD_PROC=y -CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_LITTLE_ENDIAN is not set CONFIG_KCORE_ELF=y -# CONFIG_KCORE_AOUT is not set CONFIG_ELF_KERNEL=y +CONFIG_BINFMT_IRIX=y +CONFIG_FORWARD_KEYBOARD=y # CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set CONFIG_NET=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y -# CONFIG_PARPORT is not set # # Loadable module support # CONFIG_MODULES=y -CONFIG_MODVERSIONS=y +# CONFIG_MODVERSIONS is not set CONFIG_KMOD=y # -# I2O device support +# Plug and Play configuration # -# 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 +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set # # Block devices # -CONFIG_BLK_DEV_FD=m -CONFIG_BLK_DEV_IDE=m +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set # # Please see Documentation/ide.txt for help/info on IDE drives # -# CONFIG_BLK_DEV_HD_IDE is not set -CONFIG_BLK_DEV_IDEDISK=m -# CONFIG_IDEDISK_MULTI_MODE 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 -# CONFIG_BLK_DEV_CMD640 is not set -# CONFIG_BLK_DEV_RZ1000 is not set -# CONFIG_BLK_DEV_IDEPCI is not set -# CONFIG_IDE_CHIPSETS is not set +# CONFIG_BLK_DEV_HD_ONLY is not set # # Additional Block Devices # -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_NBD=m +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_MD is not set -CONFIG_BLK_DEV_RAM=m +# CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_XD is not set -CONFIG_PARIDE_PARPORT=y # CONFIG_PARIDE is not set # CONFIG_BLK_DEV_IDE_MODES is not set # CONFIG_BLK_DEV_HD is not set @@ -102,15 +95,18 @@ # # Networking options # -# CONFIG_PACKET is not set +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set -# CONFIG_FIREWALL 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_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set @@ -120,14 +116,36 @@ # # (it is safe to leave these untouched) # -# CONFIG_INET_RARP is not set # CONFIG_SKB_LARGE 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_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC 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 # # SCSI support @@ -138,14 +156,18 @@ # SCSI support type (disk, tape, CD-ROM) # CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=m -CONFIG_BLK_DEV_SR=m +CONFIG_SD_EXTRA_DEVS=40 +CONFIG_CHR_DEV_ST=y +CONFIG_ST_EXTRA_DEVS=2 +CONFIG_BLK_DEV_SR=y # CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 # CONFIG_CHR_DEV_SG is not set # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs # +# CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_LOGGING is not set @@ -153,12 +175,14 @@ # # SCSI low-level drivers # +CONFIG_SCSI_SGIWD93=y # CONFIG_SCSI_7000FASST is not set # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -171,212 +195,162 @@ # 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_SYM53C416 is not set -# CONFIG_SCSI_NCR53C7xx is not set -CONFIG_SCSI_NCR53C8XX=y -# CONFIG_SCSI_SYM53C8XX is not set -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 -CONFIG_SCSI_NCR53C8XX_SYNC=20 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set -# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set +# CONFIG_SCSI_SIM710 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_SEAGATE is not set -# CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set + +# +# I2O device support +# +# 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 -# CONFIG_ARCNET is not set # CONFIG_DUMMY is not set -# CONFIG_EQUALIZER is not set -CONFIG_NET_ETHERNET=y -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y -CONFIG_PCNET32=y -# CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set -# CONFIG_DE4X5 is not set -# CONFIG_DEC_ELCP is not set -# CONFIG_DEC_ELCP is not set -# CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_NET_POCKET is not set -# CONFIG_FDDI is not set -# CONFIG_DLCI is not set -# CONFIG_PPP is not set # CONFIG_SLIP is not set -# CONFIG_NET_RADIO is not set -# CONFIG_TR is not set -# CONFIG_HOSTESS_SV11 is not set -# CONFIG_COSA is not set -# CONFIG_RCPCI is not set -# CONFIG_WAN_DRIVERS is not set -# CONFIG_LAPBETHER is not set -# CONFIG_X25_ASY is not set +# CONFIG_PPP is not set +CONFIG_SGISEEQ=y # -# AX.25 network device drivers +# Character devices # -# CONFIG_MKISS is not set -# CONFIG_6PACK is not set -# CONFIG_BPQETHER is not set -# CONFIG_DMASCC is not set -# CONFIG_SCC is not set -# CONFIG_BAYCOM_SER_FDX is not set -# CONFIG_BAYCOM_SER_HDX is not set -# CONFIG_BAYCOM_PAR is not set -# CONFIG_BAYCOM_EPP is not set -# CONFIG_SOUNDMODEM is not set +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 is not set +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set # -# ISDN subsystem +# I2C support # -# CONFIG_ISDN is not set +# CONFIG_I2C is not set # -# comment +# Mice # -# CONFIG_CD_NO_IDESCSI is not set +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set # -# Character devices +# Joysticks # -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_SERIAL=m -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set -# CONFIG_MOUSE is not set +# CONFIG_JOYSTICK is not set # CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# # CONFIG_WATCHDOG is not set # CONFIG_NVRAM is not set -CONFIG_RTC=y +# CONFIG_RTC is not set # # Video For Linux # # CONFIG_VIDEO_DEV is not set - -# -# Joystick support -# -# CONFIG_JOYSTICK is not set # CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set # # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set # -# USB drivers - not for the faint of heart +# USB support # # CONFIG_USB is not set # -# Filesystems +# Misc devices # -CONFIG_QUOTA=y -CONFIG_AUTOFS_FS=m + +# +# File systems +# +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_UMSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -CONFIG_MINIX_FS=m +# 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_CRAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set -CONFIG_HPFS_FS=m +# CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -CONFIG_ROMFS_FS=m +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS 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_UFS_FS is not set # # Network File Systems # # CONFIG_CODA_FS is not set -CONFIG_NFS_FS=m -CONFIG_SUNRPC=m -CONFIG_LOCKD=m +CONFIG_NFS_FS=y +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 # # Partition Types # -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_MAC_PARTITION is not set -# CONFIG_OSF_PARTITION is not set -# CONFIG_SMD_DISKLABEL is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_SGI_DISKLABEL is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_CODEPAGE_437=m -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_SGI_PARTITION=y +# CONFIG_NLS is not set # # Console drivers # -CONFIG_VGA_CONSOLE=y -# CONFIG_FB is not set -# CONFIG_FBCON_FONTWIDTH8_ONLY is not set -# CONFIG_FBCON_FONTS is not set -CONFIG_FONT_8x8=y +CONFIG_SGI_NEWPORT_CONSOLE=y CONFIG_FONT_8x16=y # @@ -385,8 +359,15 @@ # CONFIG_SOUND is not set # +# SGI devices +# +CONFIG_SGI_SERIAL=y +CONFIG_SGI_DS1286=y +# CONFIG_SGI_NEWPORT_GFX is not set + +# # Kernel hacking # -# CONFIG_CROSSCOMPILE is not set +CONFIG_CROSSCOMPILE=y # CONFIG_MIPS_FPE_MODULE is not set # CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.3.47/linux/arch/mips/defconfig-decstation linux/arch/mips/defconfig-decstation --- v2.3.47/linux/arch/mips/defconfig-decstation Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/defconfig-decstation Thu Feb 24 22:52:30 2000 @@ -0,0 +1,263 @@ +# +# Automatically generated by make menuconfig: don't edit +# + +# +# 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_DECSTATION=y +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_OLIVETTI_M700 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SNI_RM200_PCI is not set + +# +# CPU selection +# +CONFIG_CPU_R3000=y +# CONFIG_CPU_R6000 is not set +# 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_ADVANCED is not set +# CONFIG_CPU_HAS_LLSC 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_NET=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# TURBOchannel support +# +CONFIG_TC=y + +# +# 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_IDE is not set +# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP 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=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_SKB_LARGE 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_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC 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 + +# +# SCSI support +# +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_DECNCR=y +# CONFIG_SCSI_DECSII 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 +# CONFIG_DUMMY is not set +# CONFIG_SLIP is not set +# CONFIG_PPP is not set +CONFIG_DECLANCE=y + +# +# 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 is not set +# CONFIG_KEYBOARD is not set +# CONFIG_MOUSE is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Misc devices +# + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_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_BFS_FS_WRITE 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_CRAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_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_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_SYSV_FS_WRITE 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_NFS_FS 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 + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +CONFIG_OSF_PARTITION=y +# 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_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +CONFIG_ULTRIX_PARTITION=y +# CONFIG_SUN_PARTITION is not set +# CONFIG_NLS is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_MIPS_FPE_MODULE is not set +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.3.47/linux/arch/mips/defconfig-ip22 linux/arch/mips/defconfig-ip22 --- v2.3.47/linux/arch/mips/defconfig-ip22 Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/defconfig-ip22 Thu Feb 24 22:52:30 2000 @@ -0,0 +1,373 @@ +# +# Automatically generated make config: don't edit +# + +# +# 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_DECSTATION is not set +# CONFIG_DDB5074 is not set +# CONFIG_MIPS_MAGNUM_4000 is not set +# CONFIG_OLIVETTI_M700 is not set +CONFIG_SGI_IP22=y +# CONFIG_SNI_RM200_PCI is not set + +# +# CPU selection +# +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_R6000 is not set +# 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_ADVANCED is not set +CONFIG_CPU_HAS_LLSC=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=y +CONFIG_FORWARD_KEYBOARD=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +CONFIG_NET=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# 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_IDE is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_ONLY is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP 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=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# +# CONFIG_SKB_LARGE 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_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC 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 + +# +# 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=y +CONFIG_ST_EXTRA_DEVS=2 +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +CONFIG_SCSI_SGIWD93=y +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_IPS 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_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_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SIM710 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_SEAGATE is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set + +# +# I2O device support +# +# 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 +# CONFIG_DUMMY is not set +# CONFIG_SLIP is not set +# CONFIG_PPP is not set +CONFIG_SGISEEQ=y + +# +# 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 is not set +# 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=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV 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_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_AGP is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Misc devices +# + +# +# File systems +# +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y +# 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_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_CRAMFS is not set +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_MINIX_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_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS 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_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +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 + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_SGI_PARTITION=y +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_SGI_NEWPORT_CONSOLE=y +CONFIG_FONT_8x16=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# SGI devices +# +CONFIG_SGI_SERIAL=y +CONFIG_SGI_DS1286=y +# CONFIG_SGI_NEWPORT_GFX is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_MIPS_FPE_MODULE is not set +# CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.3.47/linux/arch/mips/jazz/floppy-jazz.c linux/arch/mips/jazz/floppy-jazz.c --- v2.3.47/linux/arch/mips/jazz/floppy-jazz.c Wed Feb 16 17:03:51 2000 +++ linux/arch/mips/jazz/floppy-jazz.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: floppy-jazz.c,v 1.1 1998/05/07 18:38:29 ralf Exp $ +/* $Id: floppy-jazz.c,v 1.3 2000/02/24 00:12:40 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 diff -u --recursive --new-file v2.3.47/linux/arch/mips/jazz/int-handler.S linux/arch/mips/jazz/int-handler.S --- v2.3.47/linux/arch/mips/jazz/int-handler.S Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/jazz/int-handler.S Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: int-handler.S,v 1.14 1999/05/01 22:40:34 ralf Exp $ +/* $Id: int-handler.S,v 1.15 1999/08/18 23:37:43 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 @@ -14,7 +14,6 @@ * cycle is a good cycle. */ #include -#include #include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/jazz/io.c linux/arch/mips/jazz/io.c --- v2.3.47/linux/arch/mips/jazz/io.c Fri Sep 10 23:57:27 1999 +++ linux/arch/mips/jazz/io.c Thu Feb 24 22:52:30 2000 @@ -9,7 +9,6 @@ */ #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/jazz/jazzdma.c linux/arch/mips/jazz/jazzdma.c --- v2.3.47/linux/arch/mips/jazz/jazzdma.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/jazz/jazzdma.c Thu Feb 24 22:52:30 2000 @@ -10,10 +10,11 @@ * and return the more usual NULL pointer as logical address. */ #include +#include #include #include +#include #include -#include #include #include #include @@ -27,7 +28,6 @@ #define CONF_DEBUG_VDMA 0 static unsigned long vdma_pagetable_start = 0; -static unsigned long vdma_pagetable_end = 0; /* * Debug stuff @@ -59,30 +59,31 @@ /* * Initialize the Jazz R4030 dma controller */ -unsigned long vdma_init(unsigned long memory_start, unsigned long memory_end) +void __init vdma_init(void) { - /* - * Allocate 32k of memory for DMA page tables. - * This needs to be page aligned and should be - * uncached to avoid cache flushing after every - * update. - */ - vdma_pagetable_start = KSEG1ADDR((memory_start + 4095) & ~4095); - vdma_pagetable_end = vdma_pagetable_start + VDMA_PGTBL_SIZE; - flush_cache_all(); - - /* - * Clear the R4030 translation table - */ - vdma_pgtbl_init(); - - r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE,PHYSADDR(vdma_pagetable_start)); - r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM,VDMA_PGTBL_SIZE); - r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0); + /* + * Allocate 32k of memory for DMA page tables. This needs to be page + * aligned and should be uncached to avoid cache flushing after every + * update. + */ + vdma_pagetable_start = alloc_bootmem_low_pages(VDMA_PGTBL_SIZE); + if (!vdma_pagetable_start) + BUG(); + dma_cache_wback_inv(vdma_pagetable_start, VDMA_PGTBL_SIZE); + vdma_pagetable_start = KSEG1ADDR(vdma_pagetable_start); + + /* + * Clear the R4030 translation table + */ + vdma_pgtbl_init(); + + r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE,PHYSADDR(vdma_pagetable_start)); + r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM, VDMA_PGTBL_SIZE); + r4030_write_reg32(JAZZ_R4030_TRSTBL_INV, 0); - printk("VDMA: R4030 DMA pagetables initialized.\n"); + printk("VDMA: R4030 DMA pagetables initialized.\n"); - return KSEG0ADDR(vdma_pagetable_end); + return KSEG0ADDR(vdma_pagetable_end); } /* diff -u --recursive --new-file v2.3.47/linux/arch/mips/jazz/kbd-jazz.c linux/arch/mips/jazz/kbd-jazz.c --- v2.3.47/linux/arch/mips/jazz/kbd-jazz.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/jazz/kbd-jazz.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: kbd-jazz.c,v 1.1 1998/10/28 12:38:10 ralf Exp $ +/* $Id: kbd-jazz.c,v 1.1 1999/01/03 17:50:48 ralf Exp $ * * Low-level hardware access stuff for Jazz family machines. * diff -u --recursive --new-file v2.3.47/linux/arch/mips/jazz/rtc-jazz.c linux/arch/mips/jazz/rtc-jazz.c --- v2.3.47/linux/arch/mips/jazz/rtc-jazz.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/jazz/rtc-jazz.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: rtc-jazz.c,v 1.2 1998/06/25 20:19:14 ralf Exp $ +/* $Id: rtc-jazz.c,v 1.2 1998/08/26 21:46:38 tsbogend 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 diff -u --recursive --new-file v2.3.47/linux/arch/mips/jazz/setup.c linux/arch/mips/jazz/setup.c --- v2.3.47/linux/arch/mips/jazz/setup.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/jazz/setup.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.20 1999/02/25 21:57:47 tsbogend Exp $ +/* $Id: setup.c,v 1.25 2000/01/27 01:05:23 ralf Exp $ * * Setup pointers to hardware-dependent routines. * @@ -18,11 +18,12 @@ #include #include #include +#include #include #include -#include #include #include +#include #include #include #include @@ -79,6 +80,11 @@ i8259_setup_irq(2, &irq2); } +int __init page_is_ram(unsigned long pagenr) +{ + return 1; +} + void __init jazz_setup(void) { add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K); @@ -102,8 +108,29 @@ #ifdef CONFIG_BLK_DEV_IDE ide_ops = &std_ide_ops; #endif +#ifdef CONFIG_BLK_DEV_FD + fd_ops = &jazz_fd_ops; +#endif +#ifdef CONFIG_VT conswitchp = &dummy_con; +#endif + +#warning "Somebody should check if screen_info is ok for Jazz." + + 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 */ + }; + rtc_ops = &jazz_rtc_ops; kbd_ops = &jazz_kbd_ops; - fd_ops = &jazz_fd_ops; + + vdma_init(); } diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/Makefile linux/arch/mips/kernel/Makefile --- v2.3.47/linux/arch/mips/kernel/Makefile Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/Makefile Thu Feb 24 22:52:30 2000 @@ -1,3 +1,4 @@ +# $Id: Makefile,v 1.15 2000/01/26 00:07:44 ralf Exp $ # # Makefile for the Linux/MIPS kernel. # @@ -13,11 +14,21 @@ EXTRA_ASFLAGS = -mips3 -mcpu=r4000 O_TARGET := kernel.o O_OBJS := branch.o process.o signal.o entry.o traps.o ptrace.o vm86.o \ - ioport.o pci.o reset.o setup.o syscall.o sysmips.o ipc.o \ - r4k_switch.o r4k_misc.o r4k_fpu.o r2300_switch.o r2300_misc.o \ - r2300_fpu.o r6000_fpu.o scall_o32.o softfp.o unaligned.o + ioport.o reset.o semaphore.o setup.o syscall.o sysmips.o ipc.o \ + scall_o32.o softfp.o unaligned.o OX_OBJS := mips_ksyms.o +ifdef CONFIG_CPU_R3000 +O_OBJS += r2300_misc.o r2300_fpu.o r2300_switch.o +else +O_OBJS += r4k_misc.o r4k_switch.o +ifdef CONFIG_CPU_R6000 +O_OBJS += r6000_fpu.o +else +O_OBJS += r4k_fpu.o +endif +endif + ifdef CONFIG_MIPS_FPE_MODULE M_OBJS += fpe.o endif @@ -25,10 +36,11 @@ # # SGIs have very different interrupt/timer hardware. # -ifndef CONFIG_SGI +ifndef CONFIG_SGI_IP22 ifndef CONFIG_DECSTATION ifndef CONFIG_BAGET_MIPS - O_OBJS += irq.o time.o + O_OBJS += time.o + OX_OBJS += irq.o endif endif endif @@ -61,8 +73,6 @@ # compatibility stuff between various boards and boards. # O_OBJS := $(sort $(O_OBJS)) - -all: kernel.o head.o entry.o: entry.S diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/entry.S linux/arch/mips/kernel/entry.S --- v2.3.47/linux/arch/mips/kernel/entry.S Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/entry.S Thu Feb 24 22:52:30 2000 @@ -1,20 +1,13 @@ -/* +/* $Id: entry.S,v 1.20 2000/02/23 00:41:00 ralf Exp $ + * * Low level exception 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) 1994, 1995 by Ralf Baechle - * - * $Id: entry.S,v 1.14 1999/04/12 19:13:21 harald Exp $ - */ - -/* - * entry.S contains the system-call and fault low-level handling routines. - * This also contains the timer-interrupt handler, as well as all interrupts - * and faults that can result in a task-switch. The ISA dependent TLB - * code is in arch/mips//.S + * Copyright (C) 1994 - 2000 by Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #include #include @@ -23,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -31,46 +23,45 @@ #include #include #include +#include -/* - * Heia ... The %lo, %hi and %HI stuff is too strong for the ELF assembler - * and the ABI to cope with ... - */ .text - .set noreorder - .set mips3 .align 4 -EXPORT(handle_bottom_half) - jal do_bottom_half - nop + .set push + .set reorder +EXPORT(ret_from_fork) + move a0, v0 # prev + jal schedule_tail + j ret_from_sys_call + +EXPORT(handle_softirq) + jal do_softirq b 9f - nop reschedule: jal schedule - nop EXPORT(ret_from_sys_call) EXPORT(ret_from_irq) - lw t0,bh_mask - lw t1,bh_active # unused delay slot - and t0,t1 - bnez t0,handle_bottom_half -9: lw t0,PT_STATUS(sp) # returning to kernel mode? + .type ret_from_irq,@function + lw t0, softirq_state + lw t1, softirq_state+4 # unused delay slot + and t0, t1 + bnez t0, handle_softirq + - andi t1, t0, 0x10 +9: lw t0,PT_STATUS(sp) # returning to kernel mode? + lw t2, TASK_NEED_RESCHED($28) + andi t1, t0, KU_USER beqz t1, return # -> yes - lw t1, TASK_NEED_RESCHED($28) - bnez t1, reschedule + bnez t2, reschedule lw v0, TASK_SIGPENDING($28) move a0, zero beqz v0, return - nop - jal do_signal move a1, sp + jal do_signal EXPORT(return) .set noat - RESTORE_ALL - eret + RESTORE_ALL_AND_RET .set at /* @@ -84,7 +75,9 @@ * couldn't find a cause for it. */ lui t1,%hi(spurious_count) + .set reorder lw t0,%lo(spurious_count)(t1) + .set noreorder addiu t0,1 j ret_from_irq sw t0,%lo(spurious_count)(t1) @@ -107,7 +100,9 @@ ctc1 a2,fcr31; \ STI #define __BUILD_clear_ade(exception) \ + .set reorder; \ MFC0 t0,CP0_BADVADDR; \ + .set noreorder; \ REG_S t0,PT_BVADDR(sp); \ KMODE #define __BUILD_silent(exception) @@ -122,9 +117,9 @@ #define __BUILD_count(exception) \ .set reorder; \ lw t0,exception_count_##exception; \ + .set noreorder; \ addiu t0, 1; \ sw t0,exception_count_##exception; \ - .set noreorder; \ .data; \ EXPORT(exception_count_##exception); \ .word 0; \ @@ -155,6 +150,8 @@ BUILD_HANDLER(fpe,fpe,fpe,silent) /* #15 */ BUILD_HANDLER(watch,watch,sti,verbose) /* #23 */ BUILD_HANDLER(reserved,reserved,sti,verbose) /* others */ + + .set pop /* * Table of syscalls diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/gdb-low.S linux/arch/mips/kernel/gdb-low.S --- v2.3.47/linux/arch/mips/kernel/gdb-low.S Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/gdb-low.S Thu Feb 24 22:52:30 2000 @@ -5,14 +5,13 @@ * * Copyright (C) 1995 Andreas Busse * - * $Id: gdb-low.S,v 1.4 1997/12/01 17:57:26 ralf Exp $ + * $Id: gdb-low.S,v 1.5 1999/08/18 23:37:43 ralf Exp $ */ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/head.S linux/arch/mips/kernel/head.S --- v2.3.47/linux/arch/mips/kernel/head.S Tue Sep 7 12:14:06 1999 +++ linux/arch/mips/kernel/head.S Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.11 1998/10/18 13:27:12 tsbogend Exp $ +/* $Id: head.S,v 1.17 1999/12/04 03:58:59 ralf Exp $ * * arch/mips/kernel/head.S * @@ -8,10 +8,11 @@ * * Copyright (C) 1994, 1995 Waldorf Electronics * Written by Ralf Baechle and Andreas Busse - * Copyright (C) 1995, 1996, 1997, 1998 Ralf Baechle + * Copyright (C) 1995 - 1999 Ralf Baechle * Copyright (C) 1996 Paul M. Antoine * Modified for DECStation and hence R3000 support by Paul M. Antoine - * Further modifications by David S. Miller + * 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. */ @@ -26,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -54,9 +54,8 @@ LEAF(except_vec0_r4000) .set mips3 mfc0 k0, CP0_BADVADDR # Get faulting address - _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 # get pgd only bits - lw k1, THREAD_PGDIR(k1) # get task pg_dir + lw k1, current_pgd # get pgd pointer sll k0, k0, 2 addu k1, k1, k0 # add in pgd offset mfc0 k0, CP0_CONTEXT # get context reg @@ -81,9 +80,8 @@ LEAF(except_vec0_r4600) .set mips3 mfc0 k0, CP0_BADVADDR - _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 - lw k1, THREAD_PGDIR(k1) + lw k1, current_pgd # get pgd pointer sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT @@ -109,9 +107,8 @@ LEAF(except_vec0_nevada) .set mips3 mfc0 k0, CP0_BADVADDR # Get faulting address - _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 # get pgd only bits - lw k1, THREAD_PGDIR(k1) # get task pg_dir + lw k1, current_pgd # get pgd pointer sll k0, k0, 2 addu k1, k1, k0 # add in pgd offset lw k1, (k1) @@ -135,9 +132,8 @@ LEAF(except_vec0_r45k_bvahwbug) .set mips3 mfc0 k0, CP0_BADVADDR - _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 - lw k1, THREAD_PGDIR(k1) + lw k1, current_pgd # get pgd pointer sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT @@ -166,9 +162,8 @@ LEAF(except_vec0_r4k_mphwbug) .set mips3 mfc0 k0, CP0_BADVADDR - _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 - lw k1, THREAD_PGDIR(k1) + lw k1, current_pgd # get pgd pointer sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT @@ -197,9 +192,8 @@ LEAF(except_vec0_r4k_250MHZhwbug) .set mips3 mfc0 k0, CP0_BADVADDR - _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 - lw k1, THREAD_PGDIR(k1) + lw k1, current_pgd # get pgd pointer sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT @@ -227,9 +221,8 @@ LEAF(except_vec0_r4k_MP250MHZhwbug) .set mips3 mfc0 k0, CP0_BADVADDR - _GET_CURRENT(k1) # get current task ptr srl k0, k0, 22 - lw k1, THREAD_PGDIR(k1) + lw k1, current_pgd # get pgd pointer sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT @@ -258,27 +251,22 @@ /* TLB refill, EXL == 0, R[23]00 version */ LEAF(except_vec0_r2300) + .set noat .set mips1 mfc0 k0, CP0_BADVADDR - _GET_CURRENT(k1) # get current task ptr + lw k1, current_pgd # get pgd pointer srl k0, k0, 22 - lw k1, THREAD_PGDIR(k1) sll k0, k0, 2 addu k1, k1, k0 mfc0 k0, CP0_CONTEXT lw k1, (k1) - srl k0, k0, 1 and k0, k0, 0xffc addu k1, k1, k0 lw k0, (k1) - srl k0, k0, 12 + nop mtc0 k0, CP0_ENTRYLO0 mfc0 k1, CP0_EPC tlbwr - nop - nop - nop - nop jr k1 rfe END(except_vec0_r2300) @@ -346,23 +334,25 @@ li k1, -4 and k0, k1 mtc0 zero, CP0_TAGLO - // nop;nop cache Index_Store_Tag_D,(k0) - // nop;nop 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) @@ -371,6 +361,7 @@ /* 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 @@ -408,6 +399,14 @@ probe_done: + /* + * Stack for kernel and init, current variable + */ + la $28, init_task_union + addiu t0, $28, KERNEL_STACK_SIZE-32 + sw t0, kernelsp + subu sp, t0, 4*SZREG + /* 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 @@ -423,7 +422,7 @@ jal prom_init /* prom_init(argc, argv, envp); */ nop -#ifdef CONFIG_SGI +#ifdef CONFIG_SGI_IP22 jal sgi_sysinit nop #endif @@ -441,14 +440,6 @@ jal loadmmu nop - /* - * Stack for kernel and init, current variable - */ - la $28, init_task_union - addiu t0, $28, KERNEL_STACK_SIZE-32 - sw t0, kernelsp - subu sp, t0, 4*SZREG - /* Disable coprocessors */ mfc0 t0, CP0_STATUS li t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX) @@ -598,6 +589,8 @@ .fill 32*4,1,0 EXPORT(kernelsp) + PTR 0 +EXPORT(current_pgd) PTR 0 .text diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/ipc.c linux/arch/mips/kernel/ipc.c --- v2.3.47/linux/arch/mips/kernel/ipc.c Fri May 8 00:13:23 1998 +++ linux/arch/mips/kernel/ipc.c Thu Feb 24 22:52:30 2000 @@ -20,108 +20,79 @@ /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * - * This is really horribly ugly. FIXME: Get rid of this wrapper. + * This is really horribly ugly. */ -asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +asmlinkage int sys_ipc (uint call, int first, int second, + int third, void *ptr, long fifth) { int version, ret; - lock_kernel(); version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; - if (call <= SEMCTL) - switch (call) { - case SEMOP: - ret = sys_semop (first, (struct sembuf *)ptr, second); - goto out; - case SEMGET: - ret = sys_semget (first, second, third); - goto out; - case SEMCTL: { - union semun fourth; - ret = -EINVAL; + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void **) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; if (!ptr) - goto out; - ret = -EFAULT; - if (get_user(fourth.__pad, (void **) ptr)) - goto out; - ret = sys_semctl (first, second, third, fourth); - goto out; - } - default: - ret = -EINVAL; - goto out; + return -EINVAL; + + if (copy_from_user(&tmp, + (struct ipc_kludge *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); } - if (call <= MSGCTL) - switch (call) { - case MSGSND: - ret = sys_msgsnd (first, (struct msgbuf *) ptr, - second, third); - goto out; - case MSGRCV: - switch (version) { - case 0: { - struct ipc_kludge tmp; - ret = -EINVAL; - if (!ptr) - goto out; - ret = -EFAULT; - if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, - sizeof (tmp))) - goto out; - ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); - goto out; - } - case 1: default: - ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); - goto out; - } - case MSGGET: - ret = sys_msgget ((key_t) first, second); - goto out; - case MSGCTL: - ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); - goto out; default: - ret = -EINVAL; - goto out; + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); } - if (call <= SHMCTL) - switch (call) { - case SHMAT: - switch (version) { - case 0: default: { - ulong raddr; - ret = sys_shmat (first, (char *) ptr, second, &raddr); - if (ret) - goto out; - ret = put_user (raddr, (ulong *) third); - goto out; - } - case 1: /* iBCS2 emulator entry point */ - ret = -EINVAL; - if (!segment_eq(get_fs(), get_ds())) - goto out; - ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); - goto out; - } - case SHMDT: - ret = sys_shmdt ((char *)ptr); - goto out; - case SHMGET: - ret = sys_shmget (first, second, third); - goto out; - case SHMCTL: - ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); - goto out; - default: - ret = -EINVAL; - goto out; + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, (struct msqid_ds *) ptr); + + case SHMAT: + switch (version) { + default: { + ulong raddr; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong *) third); + } + case 1: /* iBCS2 emulator entry point */ + if (!segment_eq(get_fs(), get_ds())) + return -EINVAL; + return sys_shmat (first, (char *) ptr, second, (ulong *) third); } - else - ret = -EINVAL; -out: - unlock_kernel(); - return ret; + case SHMDT: + return sys_shmdt ((char *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds *) ptr); + default: + return -EINVAL; + } } diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c --- v2.3.47/linux/arch/mips/kernel/irixelf.c Sun Jul 25 13:45:25 1999 +++ linux/arch/mips/kernel/irixelf.c Sat Feb 26 20:33:02 2000 @@ -1,4 +1,4 @@ -/* $Id: irixelf.c,v 1.17 1999/06/17 13:25:45 ralf Exp $ +/* $Id: irixelf.c,v 1.24 2000/02/04 07:40:23 ralf Exp $ * * irixelf.c: Code to load IRIX ELF executables which conform to * the MIPS ABI. @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -30,7 +31,7 @@ #include #include -#include +#include #include #include @@ -44,17 +45,13 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_irix_library(int fd); -static int irix_core_dump(long signr, struct pt_regs * regs); +static int irix_core_dump(long signr, struct pt_regs * regs, + struct file *file); extern int dump_fpu (elf_fpregset_t *); static struct linux_binfmt irix_format = { - NULL, -#ifndef MODULE - NULL, -#else - &__this_module.usecount, -#endif - load_irix_binary, load_irix_library, irix_core_dump, PAGE_SIZE + NULL, THIS_MODULE, load_irix_binary, load_irix_library, + irix_core_dump, PAGE_SIZE }; #ifndef elf_addr_t @@ -263,8 +260,8 @@ if((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine) || - (!interpreter_dentry->d_inode->i_op || - !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)) { + (!interpreter_dentry->d_inode->i_fop || + !interpreter_dentry->d_inode->i_fop->mmap)) { printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type); return 0xffffffff; } @@ -407,16 +404,14 @@ /* Check sanity of IRIX elf executable header. */ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm) { - if (ehp->e_ident[0] != 0x7f || strncmp(&ehp->e_ident[1], "ELF", 3)) { - return -ENOEXEC; - } + if (memcmp(ehp->e_ident, ELFMAG, SELFMAG) != 0) + return -ENOEXEC; /* First of all, some simple consistency checks */ if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) || !elf_check_arch(ehp->e_machine) || - (!bprm->dentry->d_inode->i_op || - !bprm->dentry->d_inode->i_op->default_file_ops || - !bprm->dentry->d_inode->i_op->default_file_ops->mmap)) { + (!bprm->dentry->d_inode->i_fop || + !bprm->dentry->d_inode->i_fop->mmap)) { return -ENOEXEC; } @@ -498,7 +493,7 @@ static inline int verify_irix_interpreter(struct elfhdr *ihp) { - if(ihp->e_ident[0] != 0x7f || strncmp(&ihp->e_ident[1], "ELF", 3)) + if (memcmp(ihp->e_ident, ELFMAG, SELFMAG) != 0) return -ELIBBAD; return 0; } @@ -625,9 +620,10 @@ has_interp = has_ephdr = 0; elf_ihdr = elf_ephdr = 0; elf_ex = *((struct elfhdr *) bprm->buf); - - if(verify_binary(&elf_ex, bprm)) - return -ENOEXEC; + retval = -ENOEXEC; + + if (verify_binary(&elf_ex, bprm)) + goto out; #ifdef DEBUG_ELF print_elfhdr(&elf_ex); @@ -635,15 +631,19 @@ /* Now read in all of the header information */ size = elf_ex.e_phentsize * elf_ex.e_phnum; + if (size > 65536) + goto out; elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL); - if (elf_phdata == NULL) - return -ENOMEM; - + if (elf_phdata == NULL) { + retval = -ENOMEM; + goto out; + } + retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata, size, 1); if (retval < 0) - goto out_phdata; - + goto out_free_ph; + #ifdef DEBUG_ELF dump_phdrs(elf_phdata, elf_ex.e_phnum); #endif @@ -669,39 +669,39 @@ elf_brk = 0; retval = open_dentry(bprm->dentry, O_RDONLY); if (retval < 0) - goto out_phdata; + goto out_free_ph; file = fget(elf_exec_fileno = retval); - + elf_stack = 0xffffffff; elf_interpreter = NULL; start_code = 0xffffffff; end_code = 0; end_data = 0; - + retval = look_for_irix_interpreter(&elf_interpreter, &interpreter_dentry, &interp_elf_ex, elf_phdata, bprm, elf_ex.e_phnum); if(retval) - goto out_file; - + goto out_free_file; + if(elf_interpreter) { retval = verify_irix_interpreter(&interp_elf_ex); if(retval) - goto out_interp; + goto out_free_interp; } - + /* OK, we are done with that, now set up the arg stuff, * and then start this sucker up. */ retval = -E2BIG; if (!bprm->sh_bang && !bprm->p) - goto out_interp; - + goto out_free_interp; + /* Flush all traces of the currently running executable */ retval = flush_old_exec(bprm); if (retval) - goto out_interp; + goto out_free_dentry; /* OK, This is the point of no return */ current->mm->end_data = 0; @@ -716,15 +716,16 @@ current->mm->rss = 0; setup_arg_pages(bprm); current->mm->start_stack = bprm->p; - + /* At this point, we assume that the image should be loaded at * fixed address, not at a variable address. */ old_fs = get_fs(); set_fs(get_ds()); - - map_executable(file, elf_phdata, elf_ex.e_phnum, &elf_stack, &load_addr, - &start_code, &elf_bss, &end_code, &end_data, &elf_brk); + + map_executable(file, elf_phdata, elf_ex.e_phnum, &elf_stack, + &load_addr, &start_code, &elf_bss, &end_code, + &end_data, &elf_brk); if(elf_interpreter) { retval = map_interpreter(elf_phdata, &interp_elf_ex, @@ -736,12 +737,12 @@ printk("Unable to load IRIX ELF interpreter\n"); send_sig(SIGSEGV, current, 0); retval = 0; - goto out_file; + goto out_free_file; } } set_fs(old_fs); - + kfree(elf_phdata); fput(file); sys_close(elf_exec_fileno); @@ -806,17 +807,20 @@ if (current->flags & PF_PTRACED) send_sig(SIGTRAP, current, 0); return 0; +out: + return retval; -out_interp: - if(elf_interpreter) { - kfree(elf_interpreter); - } -out_file: +out_free_dentry: + dput(interpreter_dentry); +out_free_interp: + if (elf_interpreter) + kfree(elf_interpreter); +out_free_file: fput(file); sys_close(elf_exec_fileno); -out_phdata: +out_free_ph: kfree (elf_phdata); - return retval; + goto out; } static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs) @@ -866,15 +870,14 @@ if (error != sizeof(elf_ex)) return -ENOEXEC; - if (elf_ex.e_ident[0] != 0x7f || - strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) + if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0) return -ENOEXEC; /* First of all, some simple consistency checks. */ if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || !elf_check_arch(elf_ex.e_machine) || - (!dentry->d_inode->i_op || - !dentry->d_inode->i_op->default_file_ops->mmap)) + (!dentry->d_inode->i_fop || + !dentry->d_inode->i_fop->mmap)) return -ENOEXEC; /* Now read in all of the header information. */ @@ -982,7 +985,7 @@ return -EACCES; if(!filp->f_op) { printk("irix_mapelf: Bogon filp!\n"); - fput(file); + fput(filp); return -EACCES; } @@ -1000,7 +1003,7 @@ if(retval != (hp->p_vaddr & 0xfffff000)) { printk("irix_mapelf: do_mmap fails with %d!\n", retval); - fput(file); + fput(filp); return retval; } } @@ -1008,7 +1011,7 @@ #ifdef DEBUG_ELF printk("irix_mapelf: Success, returning %08lx\n", user_phdrp->p_vaddr); #endif - fput(file); + fput(filp); return user_phdrp->p_vaddr; } @@ -1070,20 +1073,22 @@ static int notesize(struct memelfnote *en) { int sz; - + sz = sizeof(struct elf_note); sz += roundup(strlen(en->name), 4); sz += roundup(en->datasz, 4); - + return sz; } /* #define DEBUG */ #define DUMP_WRITE(addr, nr) \ - do { if (!dump_write(file, (addr), (nr))) return 0; } while(0) + if (!dump_write(file, (addr), (nr))) \ + goto end_coredump; #define DUMP_SEEK(off) \ - do { if (!dump_seek(file, (off))) return 0; } while(0) + if (!dump_seek(file, (off))) \ + goto end_coredump; static int writenote(struct memelfnote *men, struct file *file) { @@ -1101,6 +1106,9 @@ DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ return 1; + +end_coredump: + return 0; } #undef DUMP_WRITE #undef DUMP_SEEK @@ -1111,6 +1119,7 @@ #define DUMP_SEEK(off) \ if (!dump_seek(file, (off))) \ goto end_coredump; + /* Actual dumper. * * This is a two-pass process; first we find the offsets of the bits, @@ -1164,7 +1173,7 @@ elf.e_ident[EI_DATA] = ELFDATA2LSB; elf.e_ident[EI_VERSION] = EV_CURRENT; memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); - + elf.e_type = ET_CORE; elf.e_machine = ELF_ARCH; elf.e_version = EV_CURRENT; @@ -1255,7 +1264,7 @@ notes[2].type = NT_TASKSTRUCT; notes[2].datasz = sizeof(*current); notes[2].data = current; - + /* Try to dump the FPU. */ prstatus.pr_fpvalid = dump_fpu (&fpu); if (!prstatus.pr_fpvalid) { @@ -1266,7 +1275,7 @@ notes[3].datasz = sizeof(fpu); notes[3].data = &fpu; } - + /* Write notes phdr entry. */ { struct elf_phdr phdr; @@ -1345,34 +1354,24 @@ (off_t) file->f_pos, offset); } - end_coredump: +end_coredump: set_fs(fs); -#ifndef CONFIG_BINFMT_ELF +#ifndef CONFIG_BINFMT_IRIX MOD_DEC_USE_COUNT; #endif return has_dumped; } -int __init init_irix_binfmt(void) +static int __init init_irix_binfmt(void) { return register_binfmt(&irix_format); } -#ifdef MODULE - -int init_module(void) -{ - /* Install the COFF, ELF and XOUT loaders. - * N.B. We *rely* on the table being the right size with the - * right number of free slots... - */ - return init_irix_binfmt(); -} - - -void cleanup_module( void) +static void __exit cleanup_module(void) { /* Remove the IRIX ELF loaders. */ unregister_binfmt(&irix_format); } -#endif + +module_init(init_irix_binfmt) +module_exit(exit_irix_binfmt) diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/irixinv.c linux/arch/mips/kernel/irixinv.c --- v2.3.47/linux/arch/mips/kernel/irixinv.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/kernel/irixinv.c Thu Feb 24 22:52:30 2000 @@ -5,7 +5,7 @@ * * Miguel de Icaza, 1997. * - * $Id: irixinv.c,v 1.3 1998/04/05 11:23:51 ralf Exp $ + * $Id: irixinv.c,v 1.4 1999/10/09 00:00:58 ralf Exp $ */ #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/irixioctl.c linux/arch/mips/kernel/irixioctl.c --- v2.3.47/linux/arch/mips/kernel/irixioctl.c Tue Jul 6 10:11:40 1999 +++ linux/arch/mips/kernel/irixioctl.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: irixioctl.c,v 1.6 1999/02/06 05:12:56 adevries Exp $ +/* $Id: irixioctl.c,v 1.7 1999/09/28 22:25:46 ralf Exp $ * irixioctl.c: A fucking mess... * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c --- v2.3.47/linux/arch/mips/kernel/irixsig.c Thu Jul 22 09:47:55 1999 +++ linux/arch/mips/kernel/irixsig.c Thu Feb 24 22:52:30 2000 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: irixsig.c,v 1.11 1999/06/17 13:25:46 ralf Exp $ + * $Id: irixsig.c,v 1.14 2000/01/17 03:58:59 ralf Exp $ */ #include @@ -114,17 +114,17 @@ dump_irix5_sigctx(ctx); #endif - regs->regs[5] = 0; /* XXX sigcode XXX */ regs->regs[4] = (unsigned long) signr; + regs->regs[5] = 0; /* XXX sigcode XXX */ regs->regs[6] = regs->regs[29] = sp; regs->regs[7] = (unsigned long) ka->sa.sa_handler; - regs->regs[25] = regs->cp0_epc = current->tss.irix_trampoline; + regs->regs[25] = regs->cp0_epc = (unsigned long) ka->sa.sa_restorer; return; segv_and_exit: - lock_kernel(); - do_exit(SIGSEGV); - unlock_kernel(); + if (signr == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); } static void inline @@ -296,11 +296,12 @@ return 0; } -asmlinkage unsigned long irix_sigreturn(struct pt_regs *regs) +asmlinkage void +irix_sigreturn(struct pt_regs *regs) { struct sigctx_irix5 *context, *magic; unsigned long umask, mask; - u64 *fregs, res; + u64 *fregs; int sig, i, base = 0; sigset_t blocked; @@ -333,10 +334,10 @@ __get_user(regs->lo, &context->lo); if ((umask & 1) && context->usedfp) { - fregs = (u64 *) ¤t->tss.fpu; + fregs = (u64 *) ¤t->thread.fpu; for(i = 0; i < 32; i++) fregs[i] = (u64) context->fpregs[i]; - __get_user(current->tss.fpu.hard.control, &context->fpcsr); + __get_user(current->thread.fpu.hard.control, &context->fpcsr); } /* XXX do sigstack crapola here... XXX */ @@ -361,11 +362,7 @@ /* Unreached */ badframe: - lock_kernel(); - do_exit(SIGSEGV); - unlock_kernel(); - - return res; + force_sig(SIGSEGV, current); } struct sigact_irix5 { @@ -386,7 +383,7 @@ asmlinkage int irix_sigaction(int sig, const struct sigaction *act, - struct sigaction *oact, unsigned long trampoline) + struct sigaction *oact, void *trampoline) { struct k_sigaction new_ka, old_ka; int ret; @@ -406,15 +403,14 @@ return -EFAULT; __copy_from_user(&mask, &act->sa_mask, sizeof(sigset_t)); - new_ka.ka_restorer = NULL; - } - /* - * Hmmm... methinks IRIX libc always passes a valid trampoline - * value for all invocations of sigaction. Will have to - * investigate. POSIX POSIX, die die die... - */ - current->tss.irix_trampoline = trampoline; + /* + * Hmmm... methinks IRIX libc always passes a valid trampoline + * value for all invocations of sigaction. Will have to + * investigate. POSIX POSIX, die die die... + */ + new_ka.sa.sa_restorer = trampoline; + } /* XXX Implement SIG_SETMASK32 for IRIX compatibility */ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); @@ -512,6 +508,7 @@ spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; current->blocked = newset; + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs->regs[2] = -EINTR; @@ -795,7 +792,7 @@ error = verify_area(VERIFY_WRITE, ctx, sizeof(*ctx)); if(error) goto out; - __put_user(current->tss.irix_oldctx, &ctx->link); + __put_user(current->thread.irix_oldctx, &ctx->link); __copy_to_user(&ctx->sigmask, ¤t->blocked, sizeof(irix_sigset_t)); @@ -867,7 +864,7 @@ /* XXX fpu context, blah... */ printk("Wheee, cannot restore FPU context yet...\n"); } - current->tss.irix_oldctx = ctx->link; + current->thread.irix_oldctx = ctx->link; error = regs->regs[2]; out: diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c --- v2.3.47/linux/arch/mips/kernel/irq.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/kernel/irq.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.15 1999/02/25 21:50:49 tsbogend Exp $ +/* $Id: irq.c,v 1.20 2000/02/23 00:41:00 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -29,6 +29,7 @@ #include #include #include +#include /* * This contains the irq mask for both 8259A irq controllers, it's an @@ -72,7 +73,7 @@ } } -void disable_irq(unsigned int irq_nr) +void i8259_disable_irq(unsigned int irq_nr) { unsigned long flags; @@ -81,7 +82,7 @@ restore_flags(flags); } -void enable_irq(unsigned int irq_nr) +void i8259_enable_irq(unsigned int irq_nr) { unsigned long flags; save_and_cli(flags); @@ -123,8 +124,6 @@ return len; } -atomic_t __mips_bh_counter; - static inline void i8259_mask_and_ack_irq(int irq) { cached_irq_mask |= 1 << irq; @@ -147,7 +146,7 @@ int do_random, cpu; cpu = smp_processor_id(); - hardirq_enter(cpu); + irq_enter(cpu); if (irq >= 16) goto out; @@ -175,7 +174,7 @@ unmask_irq (irq); out: - hardirq_exit(cpu); + irq_exit(cpu); } /* @@ -191,7 +190,7 @@ int do_random, cpu; cpu = smp_processor_id(); - hardirq_enter(cpu); + irq_enter(cpu); kstat.irqs[cpu][irq]++; action = *(irq + irq_action); @@ -209,7 +208,10 @@ add_interrupt_randomness(irq); __cli(); } - hardirq_exit(cpu); + irq_exit(cpu); + + if (softirq_state[cpu].active&softirq_state[cpu].mask) + do_softirq(); /* unmasking and bottom half handling is done magically for us. */ } @@ -245,7 +247,10 @@ *p = new; if (!shared) { - unmask_irq(irq); + if (is_i8259_irq(irq)) + unmask_irq(irq); + else + nile4_enable_irq(irq_to_nile4(irq)); } restore_flags(flags); return 0; @@ -356,7 +361,7 @@ return ((irq == 2) ? 9 : irq); } -static void __init i8259_init(void) +void __init i8259_init(void) { /* Init master interrupt controller */ outb(0x11, 0x20); /* Start init sequence */ diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/mips_ksyms.c linux/arch/mips/kernel/mips_ksyms.c --- v2.3.47/linux/arch/mips/kernel/mips_ksyms.c Thu Nov 11 20:11:32 1999 +++ linux/arch/mips/kernel/mips_ksyms.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: mips_ksyms.c,v 1.19 1999/04/11 18:37:55 harald Exp $ +/* $Id: mips_ksyms.c,v 1.25 2000/02/24 00:12:40 ralf Exp $ * * Export MIPS-specific functions needed for loadable modules. * @@ -22,8 +22,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -34,6 +34,8 @@ long __len); extern long __strlen_user_nocheck_asm(const char *s); extern long __strlen_user_asm(const char *s); +extern long __strnlen_user_nocheck_asm(const char *s); +extern long __strnlen_user_asm(const char *s); EXPORT_SYMBOL(EISA_bus); @@ -53,8 +55,7 @@ EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); -EXPORT_SYMBOL(clear_page); -EXPORT_SYMBOL(__mips_bh_counter); +EXPORT_SYMBOL(_clear_page); EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); @@ -70,6 +71,8 @@ EXPORT_SYMBOL_NOVERS(__strncpy_from_user_asm); EXPORT_SYMBOL_NOVERS(__strlen_user_nocheck_asm); EXPORT_SYMBOL_NOVERS(__strlen_user_asm); +EXPORT_SYMBOL_NOVERS(__strnlen_user_nocheck_asm); +EXPORT_SYMBOL_NOVERS(__strnlen_user_asm); /* Networking helper routines. */ @@ -78,10 +81,10 @@ /* * Functions to control caches. */ -EXPORT_SYMBOL(flush_page_to_ram); -EXPORT_SYMBOL(flush_cache_all); -EXPORT_SYMBOL(dma_cache_wback_inv); -EXPORT_SYMBOL(dma_cache_inv); +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); @@ -99,7 +102,7 @@ EXPORT_SYMBOL(vdma_log2phys); #endif -#ifdef CONFIG_SGI +#ifdef CONFIG_SGI_IP22 EXPORT_SYMBOL(hpc3c0); #endif diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/pci.c linux/arch/mips/kernel/pci.c --- v2.3.47/linux/arch/mips/kernel/pci.c Sat Oct 9 11:47:50 1999 +++ linux/arch/mips/kernel/pci.c Wed Dec 31 16:00:00 1969 @@ -1,92 +0,0 @@ -/* $Id: pci.c,v 1.8 1999/05/01 22:40:36 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. - * - * MIPS implementation of PCI BIOS services for PCI support. - * - * Copyright (C) 1997, 1998 Ralf Baechle - */ -#include -#include -#include -#include -#include - -#ifdef CONFIG_PCI - -struct pci_ops *pci_ops; - -/* - * BIOS32 replacement. - */ -void __init pcibios_init(void) -{ -} - -/* - * Following the generic parts of the MIPS BIOS32 code. - */ - -int pcibios_present (void) -{ - return pci_ops != NULL; -} - -/* - * The functions below are machine specific and must be reimplimented for - * each PCI chipset configuration. We just run the hook to the machine - * specific implementation. - */ -void pcibios_fixup (void) -{ - pci_ops->pcibios_fixup(); -} - -int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned char *val) -{ - return pci_ops->pcibios_read_config_byte(bus, dev_fn, where, val); -} - -int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned short *val) -{ - return pci_ops->pcibios_read_config_word(bus, dev_fn, where, val); -} - -int pcibios_read_config_dword (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned int *val) -{ - return pci_ops->pcibios_read_config_dword(bus, dev_fn, where, val); -} - -int pcibios_write_config_byte (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned char val) -{ - return pci_ops->pcibios_write_config_byte(bus, dev_fn, where, val); -} - -int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned short val) -{ - return pci_ops->pcibios_write_config_word(bus, dev_fn, where, val); -} - -int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned int val) -{ - return pci_ops->pcibios_write_config_dword(bus, dev_fn, where, val); -} - -char * __init pcibios_setup(char *str) -{ - return str; -} - -void __init pcibios_fixup_bus(struct pci_bus *bus) -{ -} - -#endif /* defined(CONFIG_PCI) */ diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/proc.c linux/arch/mips/kernel/proc.c --- v2.3.47/linux/arch/mips/kernel/proc.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/kernel/proc.c Thu Feb 24 22:52:30 2000 @@ -32,13 +32,17 @@ 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_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_sgi_names, + mach_cobalt_names, + mach_nec_ddb_names }; unsigned int version = read_32bit_cp0_register(CP0_PRID); int len; diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c --- v2.3.47/linux/arch/mips/kernel/process.c Thu Nov 11 20:11:32 1999 +++ linux/arch/mips/kernel/process.c Thu Feb 24 22:52:30 2000 @@ -1,10 +1,11 @@ -/* $Id: process.c,v 1.12 1999/06/17 13:25:46 ralf Exp $ +/* $Id: process.c,v 1.18 2000/01/29 01:41:59 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994 - 1998 by Ralf Baechle and others. + * Copyright (C) 1994 - 1999 by Ralf Baechle and others. + * Copyright (C) 1999 Silicon Graphics, Inc. */ #include #include @@ -28,23 +29,30 @@ #include #include #include +#include -struct task_struct *last_task_used_math = NULL; - -asmlinkage void ret_from_sys_call(void); - -/* - * Do necessary setup to start up a newly executed thread. - */ -void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) +void cpu_idle(void) { - /* New thread looses kernel privileges. */ - regs->cp0_status = (regs->cp0_status & ~(ST0_CU0|ST0_KSU)) | KSU_USER; - regs->cp0_epc = pc; - regs->regs[29] = sp; - current->tss.current_ds = USER_DS; + /* endless idle loop with no priority at all */ + current->priority = 0; + current->counter = -100; + init_idle(); + + while (1) { + while (!current->need_resched) + if (wait_available) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); + schedule(); + check_pgt_cache(); + } } +struct task_struct *last_task_used_math = NULL; + +asmlinkage void ret_from_fork(void); + void exit_thread(void) { /* Forget lazy fpu state */ @@ -65,21 +73,18 @@ } } -void release_thread(struct task_struct *dead_task) -{ -} - int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { struct pt_regs * childregs; long childksp; + extern void save_fp(void*); childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32; if (last_task_used_math == current) { set_cp0_status(ST0_CU1, ST0_CU1); - r4xx0_save_fp(p); + save_fp(p); } /* set up new TSS. */ childregs = (struct pt_regs *) childksp - 1; @@ -98,22 +103,21 @@ if (childregs->cp0_status & ST0_CU0) { childregs->regs[28] = (unsigned long) p; childregs->regs[29] = childksp; - p->tss.current_ds = KERNEL_DS; + p->thread.current_ds = KERNEL_DS; } else { childregs->regs[29] = usp; - p->tss.current_ds = USER_DS; + p->thread.current_ds = USER_DS; } - p->tss.reg29 = (unsigned long) childregs; - p->tss.reg31 = (unsigned long) ret_from_sys_call; + p->thread.reg29 = (unsigned long) childregs; + p->thread.reg31 = (unsigned long) ret_from_fork; /* * New tasks loose permission to use the fpu. This accelerates context * switching for most programs since they don't use the fpu. */ - p->tss.cp0_status = read_32bit_cp0_register(CP0_STATUS) & - ~(ST0_CU3|ST0_CU2|ST0_CU1|ST0_KSU); + p->thread.cp0_status = read_32bit_cp0_register(CP0_STATUS) & + ~(ST0_CU3|ST0_CU2|ST0_CU1|KU_MASK); childregs->cp0_status &= ~(ST0_CU3|ST0_CU2|ST0_CU1); - p->mm->context = 0; return 0; } @@ -121,11 +125,11 @@ /* Fill in the fpu structure for a core dump.. */ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) { - /* We actually store the FPU info in the task->tss + /* We actually store the FPU info in the task->thread * area. */ if(regs->cp0_status & ST0_CU1) { - memcpy(r, ¤t->tss.fpu, sizeof(current->tss.fpu)); + memcpy(r, ¤t->thread.fpu, sizeof(current->thread.fpu)); return 1; } return 0; /* Task didn't use the fpu at all. */ @@ -143,7 +147,7 @@ dump->u_ssize = (current->mm->start_stack - dump->start_stack + PAGE_SIZE - 1) >> PAGE_SHIFT; memcpy(&dump->regs[0], regs, sizeof(struct pt_regs)); - memcpy(&dump->regs[EF_SIZE/4], ¤t->tss.fpu, sizeof(current->tss.fpu)); + memcpy(&dump->regs[EF_SIZE/4], ¤t->thread.fpu, sizeof(current->thread.fpu)); } /* @@ -195,15 +199,24 @@ { unsigned long schedule_frame; unsigned long pc; + if (!p || p == current || p->state == TASK_RUNNING) return 0; - /* - * The same comment as on the Alpha applies here, too ... - */ - pc = thread_saved_pc(&p->tss); - if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) { - schedule_frame = ((unsigned long *)(long)p->tss.reg30)[16]; - return (unsigned long)((unsigned long *)schedule_frame)[11]; + + pc = thread_saved_pc(&p->thread); + if (pc == (unsigned long) interruptible_sleep_on + || pc == (unsigned long) sleep_on) { + schedule_frame = ((unsigned long *)p->thread.reg30)[9]; + return ((unsigned long *)schedule_frame)[15]; + } + if (pc == (unsigned long) interruptible_sleep_on_timeout + || pc == (unsigned long) sleep_on_timeout) { + schedule_frame = ((unsigned long *)p->thread.reg30)[9]; + return ((unsigned long *)schedule_frame)[16]; } + if (pc >= first_sched && pc < last_sched) { + printk(KERN_DEBUG "Bug in %s\n", __FUNCTION__); + } + return pc; } diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c --- v2.3.47/linux/arch/mips/kernel/ptrace.c Mon Jul 5 19:44:57 1999 +++ linux/arch/mips/kernel/ptrace.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: ptrace.c,v 1.13 1999/06/17 13:25:46 ralf Exp $ +/* $Id: ptrace.c,v 1.18 1999/10/09 00:00:58 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 @@ -30,6 +30,7 @@ struct task_struct *child; unsigned int flags; int res; + extern void save_fp(void*); lock_kernel(); #if 0 @@ -136,17 +137,13 @@ break; case FPR_BASE ... FPR_BASE + 31: if (child->used_math) { - unsigned long long *fregs; - if (last_task_used_math == child) { enable_cp1(); - r4xx0_save_fp(child); + save_fp(child); disable_cp1(); last_task_used_math = NULL; } - fregs = (unsigned long long *) - &child->tss.fpu.hard.fp_regs[0]; - tmp = (unsigned long) fregs[(addr - 32)]; + tmp = child->thread.fpu.hard.fp_regs[addr - 32]; } else { tmp = -1; /* FP not yet used */ } @@ -167,11 +164,17 @@ tmp = regs->lo; break; case FPC_CSR: - tmp = child->tss.fpu.hard.control; + tmp = child->thread.fpu.hard.control; break; - case FPC_EIR: /* implementation / version register */ - tmp = 0; /* XXX */ + case FPC_EIR: { /* implementation / version register */ + unsigned int flags; + + __save_flags(flags); + enable_cp1(); + __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); + __restore_flags(flags); break; + } default: tmp = 0; res = -EIO; @@ -191,33 +194,35 @@ goto out; case PTRACE_POKEUSR: { - unsigned long long *fregs; struct pt_regs *regs; int res = 0; + regs = (struct pt_regs *) ((unsigned long) child + + KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs)); switch (addr) { case 0 ... 31: - regs = (struct pt_regs *) ((unsigned long) child + - KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs)); + regs->regs[addr] = data; break; - case FPR_BASE ... FPR_BASE + 31: + case FPR_BASE ... FPR_BASE + 31: { + unsigned int *fregs; if (child->used_math) { if (last_task_used_math == child) { enable_cp1(); - r4xx0_save_fp(child); + save_fp(child); disable_cp1(); last_task_used_math = NULL; + regs->cp0_status &= ~ST0_CU1; } } else { /* FP not yet used */ - memset(&child->tss.fpu.hard, ~0, - sizeof(child->tss.fpu.hard)); - child->tss.fpu.hard.control = 0; + memset(&child->thread.fpu.hard, ~0, + sizeof(child->thread.fpu.hard)); + child->thread.fpu.hard.control = 0; } - fregs = (unsigned long long *) - &child->tss.fpu.hard.fp_regs[0]; - fregs[(addr - 32)] = (unsigned long long) data; + fregs = child->thread.fpu.hard.fp_regs; + fregs[addr - FPR_BASE] = data; break; + } case PC: regs->cp0_epc = data; break; @@ -228,7 +233,7 @@ regs->lo = data; break; case FPC_CSR: - child->tss.fpu.hard.control = data; + child->thread.fpu.hard.control = data; break; default: /* The rest are not allowed. */ diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/r2300_fpu.S linux/arch/mips/kernel/r2300_fpu.S --- v2.3.47/linux/arch/mips/kernel/r2300_fpu.S Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/r2300_fpu.S Thu Feb 24 22:52:30 2000 @@ -1,4 +1,5 @@ -/* $Id: r2300_fpu.S,v 1.5 1999/05/01 22:40:36 ralf Exp $ +/* $Id: r2300_fpu.S,v 1.7 1999/09/28 22:25:47 ralf Exp $ + * * r2300_fpu.S: Save/restore floating point context for signal handlers. * * This file is subject to the terms and conditions of the GNU General Public @@ -14,6 +15,7 @@ * Copyright (c) 1998 Harald Koerfgen */ #include +#include #include #include #include @@ -28,8 +30,8 @@ .set noreorder .set mips1 /* Save floating point context */ -LEAF(r2300_save_fp_context) - +LEAF(save_fp_context) + li v0, 0 # assume success cfc1 t1,fcr31 EX(swc1 $f0,(SC_FPREGS+0)(a0)) EX(swc1 $f1,(SC_FPREGS+8)(a0)) @@ -69,7 +71,7 @@ .set nomacro EX(sw t0,SC_FPC_EIR(a0)) .set macro - END(r2300_save_fp_context) + END(save_fp_context) /* * Restore FPU state: @@ -80,7 +82,8 @@ * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ -LEAF(r2300_restore_fp_context) +LEAF(restore_fp_context) + li v0, 0 # assume success EX(lw t0,SC_FPC_CSR(a0)) EX(lwc1 $f0,(SC_FPREGS+0)(a0)) EX(lwc1 $f1,(SC_FPREGS+8)(a0)) @@ -116,4 +119,10 @@ EX(lwc1 $f31,(SC_FPREGS+248)(a0)) jr ra ctc1 t0,fcr31 - END(r2300_restore_fp_context) + END(restore_fp_context) + + .type fault@function + .ent fault +fault: li v0, -EFAULT + jr ra + .end fault diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/r2300_misc.S linux/arch/mips/kernel/r2300_misc.S --- v2.3.47/linux/arch/mips/kernel/r2300_misc.S Wed Jun 30 11:24:54 1999 +++ linux/arch/mips/kernel/r2300_misc.S Thu Feb 24 22:52:30 2000 @@ -1,5 +1,5 @@ -/* $Id: r2300_misc.S,v 1.3 1999/05/01 22:40:36 ralf Exp $ - * r2300_misc.S: Misc. exception handling code for R3000/R2000. +/* $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 * @@ -8,14 +8,15 @@ * * Further modifications to make this work: * Copyright (c) 1998 Harald Koerfgen - * Copyright (c) 1998 Gleb Raiko & Vladimir Roganov + * Copyright (c) 1998, 1999 Gleb Raiko & Vladimir Roganov */ +#include + #include #include #include #include #include -#include #include #include #include @@ -38,11 +39,10 @@ */ #define LOAD_PTE(pte, ptr) \ mfc0 pte, CP0_BADVADDR; \ - _GET_CURRENT(ptr); \ + lw ptr, current_pgd; \ srl pte, pte, 22; \ - lw ptr, THREAD_PGDIR(ptr); \ sll pte, pte, 2; \ - addu ptr, pte, ptr; \ + addu ptr, ptr, pte; \ mfc0 pte, CP0_CONTEXT; \ lw ptr, (ptr); \ andi pte, pte, 0xffc; \ @@ -115,56 +115,67 @@ _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(r2300_handle_tlbl, PT_SIZE, sp) +NESTED(handle_tlbl, PT_SIZE, sp) .set noat #ifndef NOTLB_OPTIMIZE /* Test present bit in entry. */ LOAD_PTE(k0, k1) tlbp - nop PTE_PRESENT(k0, k1, nopage_tlbl) PTE_MAKEVALID(k0, k1) PTE_RELOAD(k1) - tlbwi - nop - mfc0 k0, CP0_EPC - nop - jr k0 - rfe + TLB_WRITE(k0) + RET(k0) nopage_tlbl: #endif DO_FAULT(0) -END(r2300_handle_tlbl) +END(handle_tlbl) -NESTED(r2300_handle_tlbs, PT_SIZE, sp) +NESTED(handle_tlbs, PT_SIZE, sp) .set noat #ifndef NOTLB_OPTIMIZE LOAD_PTE(k0, k1) tlbp # find faulting entry - nop PTE_WRITABLE(k0, k1, nopage_tlbs) PTE_MAKEWRITE(k0, k1) PTE_RELOAD(k1) - tlbwi - nop - mfc0 k0, CP0_EPC - nop - jr k0 - rfe + TLB_WRITE(k0) + RET(k0) nopage_tlbs: #endif DO_FAULT(1) -END(r2300_handle_tlbs) +END(handle_tlbs) .align 5 -NESTED(r2300_handle_mod, PT_SIZE, sp) +NESTED(handle_mod, PT_SIZE, sp) .set noat #ifndef NOTLB_OPTIMIZE LOAD_PTE(k0, k1) @@ -181,15 +192,10 @@ /* Now reload the entry into the tlb. */ PTE_RELOAD(k1) - nop tlbwi - nop - mfc0 k0, CP0_EPC - nop - jr k0 - rfe + RET(k0) #endif nowrite_mod: DO_FAULT(1) -END(r2300_handle_mod) +END(handle_mod) diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/r2300_switch.S linux/arch/mips/kernel/r2300_switch.S --- v2.3.47/linux/arch/mips/kernel/r2300_switch.S Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/r2300_switch.S Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: r2300_switch.S,v 1.6 1999/06/13 16:30:32 ralf Exp $ +/* $Id: r2300_switch.S,v 1.9 1999/10/12 17:33:49 harald Exp $ * * r2300_switch.S: R2300 specific task switching code. * @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -34,7 +33,7 @@ * task_struct *r4xx0_resume(task_struct *prev, * task_struct *next) */ -LEAF(r2300_resume) +LEAF(resume) .set reorder mfc0 t1, CP0_STATUS .set noreorder @@ -56,15 +55,11 @@ lw a2, THREAD_STATUS($28) nor a3, $0, a3 and a2, a3 - lw a3, TASK_MM($28) or a2, t1 - lw a3, MM_CONTEXT(a3) mtc0 a2, CP0_STATUS - andi a3, 0xfc0 - mtc0 a3, CP0_ENTRYHI jr ra move v0, a0 - END(r2300_resume) + END(resume) /* * Do lazy fpu context switch. Saves FPU context to the process in a0 @@ -73,7 +68,7 @@ #define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS) -LEAF(r2300_lazy_fpu_switch) +LEAF(lazy_fpu_switch) mfc0 t0, CP0_STATUS # enable cp1 li t3, 0x20000000 or t0, t3 @@ -87,24 +82,24 @@ and t1, t3 sw t1, ST_OFF(a0) swc1 $f0, (THREAD_FPU + 0x00)(a0) - FPU_SAVE(a0, t1) # clobbers t1 + FPU_SAVE_SINGLE(a0, t1) # clobbers t1 2: lwc1 $f0, (THREAD_FPU + 0x00)($28) .set reorder - FPU_RESTORE($28, t0) # clobbers t0 + FPU_RESTORE_SINGLE($28, t0) # clobbers t0 jr ra - END(r2300_lazy_fpu_switch) + END(lazy_fpu_switch) /* * Save a thread's fp context. */ .set noreorder -LEAF(r2300_save_fp) - FPU_SAVE(a0, t1) # clobbers t1 +LEAF(save_fp) + FPU_SAVE_SINGLE(a0, t1) # clobbers t1 jr ra swc1 $f0, (THREAD_FPU + 0x00)(a0) - END(r2300_save_fp) + END(save_fp) /* * Load the FPU with signalling NANS. This bit pattern we're using has @@ -116,7 +111,7 @@ #define FPU_DEFAULT 0x00000000 -LEAF(r2300_init_fpu) +LEAF(init_fpu) mfc0 t0, CP0_STATUS li t1, 0x20000000 or t0, t1 @@ -160,4 +155,4 @@ mtc1 t0, $f30 jr ra mtc1 t0, $f31 - END(r2300_init_fpu) + END(init_fpu) diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/r4k_fpu.S linux/arch/mips/kernel/r4k_fpu.S --- v2.3.47/linux/arch/mips/kernel/r4k_fpu.S Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/r4k_fpu.S Thu Feb 24 22:52:30 2000 @@ -1,4 +1,5 @@ -/* +/* $Id: r4k_fpu.S,v 1.8 1999/09/28 22:25:47 ralf Exp $ + * * r4k_fpu.S: Save/restore floating point context for signal handlers. * * This file is subject to the terms and conditions of the GNU General Public @@ -9,10 +10,9 @@ * * Multi-arch abstraction and asm macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - * $Id: r4k_fpu.S,v 1.5 1999/05/01 22:40:36 ralf Exp $ */ #include +#include #include #include #include @@ -21,35 +21,15 @@ #define EX(a,b) \ 9: a,##b; \ .section __ex_table,"a"; \ - PTR 9b,bad_stack; \ + PTR 9b, fault; \ .previous .set noreorder .set mips3 /* Save floating point context */ -LEAF(r4k_save_fp_context) - mfc0 t1,CP0_STATUS - sll t2,t1,5 - - bgez t2,1f - cfc1 t1,fcr31 - /* Store the 16 odd double precision registers */ - EX(sdc1 $f1,(SC_FPREGS+8)(a0)) - EX(sdc1 $f3,(SC_FPREGS+24)(a0)) - EX(sdc1 $f5,(SC_FPREGS+40)(a0)) - EX(sdc1 $f7,(SC_FPREGS+56)(a0)) - EX(sdc1 $f9,(SC_FPREGS+72)(a0)) - EX(sdc1 $f11,(SC_FPREGS+88)(a0)) - EX(sdc1 $f13,(SC_FPREGS+104)(a0)) - EX(sdc1 $f15,(SC_FPREGS+120)(a0)) - EX(sdc1 $f17,(SC_FPREGS+136)(a0)) - EX(sdc1 $f19,(SC_FPREGS+152)(a0)) - EX(sdc1 $f21,(SC_FPREGS+168)(a0)) - EX(sdc1 $f23,(SC_FPREGS+184)(a0)) - EX(sdc1 $f25,(SC_FPREGS+200)(a0)) - EX(sdc1 $f27,(SC_FPREGS+216)(a0)) - EX(sdc1 $f29,(SC_FPREGS+232)(a0)) - EX(sdc1 $f31,(SC_FPREGS+248)(a0)) +LEAF(save_fp_context) + li v0, 0 # assume success + cfc1 t1,fcr31 /* Store the 16 even double precision registers */ 1: @@ -76,7 +56,7 @@ .set nomacro EX(sw t0,SC_FPC_EIR(a0)) .set macro - END(r4k_save_fp_context) + END(save_fp_context) /* * Restore FPU state: @@ -87,31 +67,9 @@ * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ -LEAF(r4k_restore_fp_context) - mfc0 t1, CP0_STATUS - sll t0,t1,5 - bgez t0,1f - EX(lw t0,SC_FPC_CSR(a0)) - - /* Restore the 16 odd double precision registers only - * when enabled in the cp0 status register. - */ - EX(ldc1 $f1,(SC_FPREGS+8)(a0)) - EX(ldc1 $f3,(SC_FPREGS+24)(a0)) - EX(ldc1 $f5,(SC_FPREGS+40)(a0)) - EX(ldc1 $f7,(SC_FPREGS+56)(a0)) - EX(ldc1 $f9,(SC_FPREGS+72)(a0)) - EX(ldc1 $f11,(SC_FPREGS+88)(a0)) - EX(ldc1 $f13,(SC_FPREGS+104)(a0)) - EX(ldc1 $f15,(SC_FPREGS+120)(a0)) - EX(ldc1 $f17,(SC_FPREGS+136)(a0)) - EX(ldc1 $f19,(SC_FPREGS+152)(a0)) - EX(ldc1 $f21,(SC_FPREGS+168)(a0)) - EX(ldc1 $f23,(SC_FPREGS+184)(a0)) - EX(ldc1 $f25,(SC_FPREGS+200)(a0)) - EX(ldc1 $f27,(SC_FPREGS+216)(a0)) - EX(ldc1 $f29,(SC_FPREGS+232)(a0)) - EX(ldc1 $f31,(SC_FPREGS+248)(a0)) +LEAF(restore_fp_context) + li v0, 0 # assume success + EX(lw t0,SC_FPC_CSR(a0)) /* * Restore the 16 even double precision registers @@ -135,4 +93,10 @@ EX(ldc1 $f30,(SC_FPREGS+240)(a0)) jr ra ctc1 t0,fcr31 - END(r4k_restore_fp_context) + END(restore_fp_context) + + .type fault@function + .ent fault +fault: li v0, -EFAULT + jr ra + .end fault diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/r4k_misc.S linux/arch/mips/kernel/r4k_misc.S --- v2.3.47/linux/arch/mips/kernel/r4k_misc.S Mon Jul 5 20:35:17 1999 +++ linux/arch/mips/kernel/r4k_misc.S Thu Feb 24 22:52:30 2000 @@ -1,12 +1,11 @@ -/* +/* $Id: r4k_misc.S,v 1.9 1999/12/04 03:59:00 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) - * - * $Id: r4k_misc.S,v 1.4 1997/12/01 17:57:30 ralf Exp $ */ #include #include @@ -14,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -33,10 +31,9 @@ #define LOAD_PTE(pte, ptr) \ mfc0 pte, CP0_BADVADDR; \ srl pte, pte, 22; \ - _GET_CURRENT(ptr); \ + lw ptr, current_pgd; \ sll pte, pte, 2; \ - lw ptr, THREAD_PGDIR(ptr); \ - addu ptr, pte, ptr; \ + addu ptr, ptr, pte; \ mfc0 pte, CP0_BADVADDR; \ lw ptr, (ptr); \ srl pte, pte, 10; \ @@ -60,7 +57,6 @@ #define DO_FAULT(write) \ .set noat; \ - .set macro; \ SAVE_ALL; \ mfc0 a2, CP0_BADVADDR; \ STI; \ @@ -70,8 +66,7 @@ li a1, write; \ j ret_from_sys_call; \ nop; \ - .set noat; \ - .set nomacro; + .set noat; /* Check is PTE is present, if not then jump to LABEL. * PTR points to the page table where this PTE is located, @@ -136,9 +131,8 @@ * of the instruction cache else you get bogus results. */ .align 5 - NESTED(r4k_handle_tlbl, PT_SIZE, sp) + NESTED(handle_tlbl, PT_SIZE, sp) .set noat - .set nomacro invalid_tlbl: #ifndef NOTLB_OPTIMIZE /* Test present bit in entry. */ @@ -158,10 +152,10 @@ nopage_tlbl: DO_FAULT(0) - END(r4k_handle_tlbl) + END(handle_tlbl) .align 5 - NESTED(r4k_handle_tlbs, PT_SIZE, sp) + NESTED(handle_tlbs, PT_SIZE, sp) .set noat #ifndef NOTLB_OPTIMIZE LOAD_PTE(k0, k1) @@ -180,10 +174,10 @@ nopage_tlbs: DO_FAULT(1) - END(r4k_handle_tlbs) + END(handle_tlbs) .align 5 - NESTED(r4k_handle_mod, PT_SIZE, sp) + NESTED(handle_mod, PT_SIZE, sp) .set noat #ifndef NOTLB_OPTIMIZE LOAD_PTE(k0, k1) @@ -212,4 +206,4 @@ nowrite_mod: DO_FAULT(1) - END(r4k_handle_mod) + END(handle_mod) diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/r4k_switch.S linux/arch/mips/kernel/r4k_switch.S --- v2.3.47/linux/arch/mips/kernel/r4k_switch.S Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/r4k_switch.S Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: r4k_switch.S,v 1.7 1999/06/13 16:30:32 ralf Exp $ +/* $Id: r4k_switch.S,v 1.10 1999/10/09 00:00:58 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 @@ -7,13 +7,13 @@ * Copyright (C) 1994, 1995, 1996, 1998, 1999 by Ralf Baechle * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1994, 1995, 1996, by Andreas Busse + * Copyright (C) 1999 Silicon Graphics, Inc. */ #include #include #include #include #include -#include #include #include #include @@ -24,14 +24,14 @@ #include + .set mips3 + /* - * task_struct *r4xx0_resume(task_struct *prev, - * task_struct *next) + * task_struct *r4xx0_resume(task_struct *prev, task_struct *next) */ .set noreorder - .set mips3 .align 5 - LEAF(r4xx0_resume) + LEAF(resume) mfc0 t1, CP0_STATUS sw t1, THREAD_STATUS(a0) CPU_SAVE_NONSCRATCH(a0) @@ -51,15 +51,11 @@ lw a2, THREAD_STATUS($28) nor a3, $0, a3 and a2, a3 - lw a3, TASK_MM($28) or a2, t1 - lw a3, MM_CONTEXT(a3) mtc0 a2, CP0_STATUS - andi a3, a3, 0xff - mtc0 a3, CP0_ENTRYHI jr ra move v0, a0 - END(r4xx0_resume) + END(resume) /* * Do lazy fpu context switch. Saves FPU context to the process in a0 @@ -68,7 +64,7 @@ #define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS) -LEAF(r4xx0_lazy_fpu_switch) +LEAF(lazy_fpu_switch) mfc0 t0, CP0_STATUS # enable cp1 li t3, 0x20000000 or t0, t3 @@ -76,42 +72,27 @@ beqz a0, 2f # Save floating point state nor t3, zero, t3 + lw t1, ST_OFF(a0) # last thread looses fpu and t1, t3 sw t1, ST_OFF(a0) - sll t2, t1, 5 - bgez t2, 1f - sdc1 $f0, (THREAD_FPU + 0x00)(a0) - FPU_SAVE_16ODD(a0) -1: - FPU_SAVE_16EVEN(a0, t1) # clobbers t1 + + + FPU_SAVE_DOUBLE(a0, t1) # clobbers t1 2: - sll t0, t0, 5 # load new fp state - bgez t0, 1f - ldc1 $f0, (THREAD_FPU + 0x00)($28) - FPU_RESTORE_16ODD($28) -1: .set reorder - FPU_RESTORE_16EVEN($28, t0) # clobbers t0 + FPU_RESTORE_DOUBLE($28, t0) # clobbers t0 jr ra - END(r4xx0_lazy_fpu_switch) + END(lazy_fpu_switch) /* * Save a thread's fp context. */ - .set noreorder -LEAF(r4xx0_save_fp) - mfc0 t0, CP0_STATUS - sll t1, t0, 5 - bgez t1, 1f # 16 register mode? - nop - FPU_SAVE_16ODD(a0) -1: - FPU_SAVE_16EVEN(a0, t1) # clobbers t1 +LEAF(save_fp) + FPU_SAVE_DOUBLE(a0, t1) # clobbers t1 jr ra - sdc1 $f0, (THREAD_FPU + 0x00)(a0) - END(r4xx0_save_fp) + END(save_fp) /* * Load the FPU with signalling NANS. This bit pattern we're using has @@ -123,37 +104,18 @@ #define FPU_DEFAULT 0x00000000 -LEAF(r4xx0_init_fpu) +LEAF(init_fpu) mfc0 t0, CP0_STATUS li t1, 0x20000000 or t0, t1 mtc0 t0, CP0_STATUS - sll t0, t0, 5 li t1, FPU_DEFAULT ctc1 t1, fcr31 - bgez t0, 1f # 16 / 32 register mode? - li t0, -1 - - dmtc1 t0, $f1 - dmtc1 t0, $f3 - dmtc1 t0, $f5 - dmtc1 t0, $f7 - dmtc1 t0, $f9 - dmtc1 t0, $f11 - dmtc1 t0, $f13 - dmtc1 t0, $f15 - dmtc1 t0, $f17 - dmtc1 t0, $f19 - dmtc1 t0, $f21 - dmtc1 t0, $f23 - dmtc1 t0, $f25 - dmtc1 t0, $f27 - dmtc1 t0, $f29 - dmtc1 t0, $f31 + li t0, -1 -1: dmtc1 t0, $f0 + dmtc1 t0, $f0 dmtc1 t0, $f2 dmtc1 t0, $f4 dmtc1 t0, $f6 @@ -168,6 +130,8 @@ dmtc1 t0, $f24 dmtc1 t0, $f26 dmtc1 t0, $f28 + .set noreorder jr ra dmtc1 t0, $f30 - END(r4xx0_init_fpu) + .set reorder + END(init_fpu) diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/r6000_fpu.S linux/arch/mips/kernel/r6000_fpu.S --- v2.3.47/linux/arch/mips/kernel/r6000_fpu.S Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/r6000_fpu.S Thu Feb 24 22:52:30 2000 @@ -10,7 +10,7 @@ * Multi-arch abstraction and asm macros for easier reading: * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: r6000_fpu.S,v 1.5 1999/05/01 22:40:37 ralf Exp $ + * $Id: r6000_fpu.S,v 1.6 1999/08/09 19:43:15 harald Exp $ */ #include #include @@ -21,7 +21,7 @@ .set noreorder .set mips2 /* Save floating point context */ - LEAF(r6000_save_fp_context) + LEAF(save_fp_context) mfc0 t0,CP0_STATUS sll t0,t0,2 bgez t0,1f @@ -49,7 +49,7 @@ sw t0,SC_FPC_CSR(a0) 1: jr ra nop - END(r6000_save_fp_context) + END(save_fp_context) /* Restore FPU state: * - fp gp registers @@ -59,7 +59,7 @@ * frame on the current content of c0_status, not on the content of the * stack frame which might have been changed by the user. */ - LEAF(r6000_restore_fp_context) + LEAF(restore_fp_context) mfc0 t0,CP0_STATUS sll t0,t0,2 @@ -86,4 +86,4 @@ ctc1 t0,fcr31 1: jr ra nop - END(r6000_restore_fp_context) + END(restore_fp_context) diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/scall_o32.S linux/arch/mips/kernel/scall_o32.S --- v2.3.47/linux/arch/mips/kernel/scall_o32.S Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/scall_o32.S Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: scall_o32.S,v 1.4 1998/06/25 20:01:01 ralf Exp $ +/* $Id: scall_o32.S,v 1.11 2000/02/23 01:33:55 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 @@ -12,6 +12,7 @@ #include #include #include +#include #include /* This duplicates the definition from */ @@ -48,6 +49,7 @@ bgez t0, stackargs stack_done: + sw a3, PT_R26(sp) # save for syscall restart lw t0, TASK_FLAGS($28) # syscall tracing enabled? andi t0, PF_TRACESYS bnez t0, trace_a_syscall @@ -64,13 +66,13 @@ 1: sw v0, PT_R2(sp) # result EXPORT(o32_ret_from_sys_call) - lw t0,bh_mask - lw t1,bh_active # unused delay slot - and t0,t1 - bnez t0,o32_handle_bottom_half + lw t0, softirq_state + lw t1, softirq_state+4 # unused delay slot + and t0, t1 + bnez t0, o32_handle_softirq 9: lw t0,PT_STATUS(sp) # returning to kernel mode? - andi t1, t0, 0x10 + andi t1, t0, KU_USER lw t2, TASK_NEED_RESCHED($28) beqz t1, o32_return # -> yes bnez t2, o32_reschedule @@ -83,13 +85,10 @@ o32_return: RESTORE_SOME - RESTORE_SP - .set mips3 - eret - .set mips0 + RESTORE_SP_AND_RET -o32_handle_bottom_half: - jal do_bottom_half +o32_handle_softirq: + jal do_softirq b 9b o32_reschedule: SAVE_STATIC @@ -100,9 +99,9 @@ trace_a_syscall: SAVE_STATIC - sw t2,PT_R1(sp) + sw t2, PT_R1(sp) jal syscall_trace - lw t2,PT_R1(sp) + lw t2, PT_R1(sp) lw a0, PT_R4(sp) # Restore argument registers lw a1, PT_R5(sp) @@ -140,15 +139,28 @@ lw t0, PT_R29(sp) # get old user stack pointer la t1, 3f # copy 1 to 2 arguments - sll t3, t3, 3 + sll t3, t3, 4 subu t1, t3 jr t1 /* Ok, copy the args from the luser stack to the kernel stack */ + /* + * I know Ralf doesn't like nops but this avoids code + * duplication for R3000 targets (and this is the + * only place where ".set reorder" doesn't help). + * Harald. + */ + .set push + .set noreorder 1: lw t1, 20(t0) # argument #6 from usp + nop sw t1, 20(sp) + nop 2: lw t1, 16(t0) # argument #5 from usp + nop sw t1, 16(sp) + nop + .set pop 3: j stack_done # go back @@ -177,3 +189,4 @@ li t0, 1 # set error flag sw t0, PT_R7(sp) j ret_from_sys_call + END(handle_sys) diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/semaphore.c linux/arch/mips/kernel/semaphore.c --- v2.3.47/linux/arch/mips/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/kernel/semaphore.c Thu Feb 24 22:52:30 2000 @@ -0,0 +1,240 @@ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} + +/* + * RW Semaphores + */ +void +__down_read(struct rw_semaphore *sem, int count) +{ + DOWN_VAR; + + retry_down: + if (count < 0) { + /* Wait for the lock to become unbiased. Readers + are non-exclusive. */ + + /* This takes care of granting the lock. */ + up_read(sem); + + add_wait_queue(&sem->wait, &wait); + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (atomic_read(&sem->count) >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + mb(); + count = atomic_dec_return(&sem->count); + if (count <= 0) + goto retry_down; + } else { + add_wait_queue(&sem->wait, &wait); + + while (1) { + if (test_and_clear_bit(0, &sem->granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if ((sem->granted & 1) == 0) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + } +} + +void +__down_write(struct rw_semaphore *sem, int count) +{ + DOWN_VAR; + + retry_down: + if (count + RW_LOCK_BIAS < 0) { + up_write(sem); + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, (TASK_UNINTERRUPTIBLE + | TASK_EXCLUSIVE)); + if (atomic_read(&sem->count) >= RW_LOCK_BIAS) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + mb(); + count = atomic_sub_return(RW_LOCK_BIAS, &sem->count); + if (count != 0) + goto retry_down; + } else { + /* Put ourselves at the end of the list. */ + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); + + while (1) { + if (test_and_clear_bit(1, &sem->granted)) + break; + set_task_state(tsk, (TASK_UNINTERRUPTIBLE + | TASK_EXCLUSIVE)); + if ((sem->granted & 2) == 0) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* If the lock is currently unbiased, awaken the sleepers. + FIXME: This wakes up the readers early in a bit of a + stampede -> bad! */ + if (atomic_read(&sem->count) >= 0) + wake_up(&sem->wait); + } +} + +void +__rwsem_wake(struct rw_semaphore *sem, unsigned long readers) +{ + if (readers) { + if (test_and_set_bit(0, &sem->granted)) + BUG(); + wake_up(&sem->wait); + } else { + if (test_and_set_bit(1, &sem->granted)) + BUG(); + wake_up(&sem->write_bias_wait); + } +} diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c --- v2.3.47/linux/arch/mips/kernel/setup.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/kernel/setup.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.16 1999/06/17 13:25:47 ralf Exp $ +/* $Id: setup.c,v 1.22 2000/01/27 01:05:23 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -39,7 +39,7 @@ #include #include #include -#ifdef CONFIG_SGI +#ifdef CONFIG_SGI_IP22 #include #endif @@ -66,16 +66,7 @@ */ int EISA_bus = 0; -/* - * Milo passes some information to the kernel that looks like as if it - * had been returned by a Intel PC BIOS. Milo doesn't fill the passed - * drive_info and Linux can find out about this anyway, so I'm going to - * remove this sometime. screen_info contains information about the - * resolution of the text screen. For VGA graphics based machine this - * information is being use to continue the screen output just below - * the BIOS printed text and with the same text resolution. - */ -struct screen_info screen_info = DEFAULT_SCREEN_INFO; +struct screen_info screen_info; #ifdef CONFIG_BLK_DEV_FD extern struct fd_ops no_fd_ops; @@ -106,13 +97,6 @@ unsigned char aux_device_present; extern int _end; -extern char empty_zero_page[PAGE_SIZE]; - -/* - * This is set up by the setup-routine at boot-time - */ -#define PARAM empty_zero_page - static char command_line[CL_SIZE] = { 0, }; char saved_command_line[CL_SIZE]; extern char arcs_cmdline[CL_SIZE]; @@ -140,10 +124,8 @@ panic("Unknown machtype in init_IRQ"); } -void __init setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p) +void __init setup_arch(char **cmdline_p) { - unsigned long memory_end; #ifdef CONFIG_BLK_DEV_INITRD unsigned long tmp; unsigned long *initrd_header; @@ -155,6 +137,7 @@ void jazz_setup(void); void sni_rm200_pci_setup(void); void sgi_setup(void); + void ddb_setup(void); /* Save defaults for configuration-dependent routines. */ irq_setup = default_irq_setup; @@ -192,7 +175,8 @@ jazz_setup(); break; #endif -#ifdef CONFIG_SGI +#ifdef CONFIG_SGI_IP22 + /* As of now this is only IP22. */ case MACH_GROUP_SGI: sgi_setup(); break; @@ -202,29 +186,23 @@ sni_rm200_pci_setup(); break; #endif +#ifdef CONFIG_DDB5074 + case MACH_GROUP_NEC_DDB: + ddb_setup(); + break; +#endif default: panic("Unsupported architecture"); } - memory_end = mips_memory_upper; - /* - * Due to prefetching and similar mechanism the CPU sometimes - * generates addresses beyond the end of memory. We leave the size - * of one cache line at the end of memory unused to make shure we - * don't catch this type of bus errors. - */ - memory_end -= 128; - memory_end &= PAGE_MASK; - strncpy (command_line, arcs_cmdline, CL_SIZE); memcpy(saved_command_line, command_line, CL_SIZE); saved_command_line[CL_SIZE-1] = '\0'; *cmdline_p = command_line; - *memory_start_p = (unsigned long) &_end; - *memory_end_p = memory_end; #ifdef CONFIG_BLK_DEV_INITRD +#error "Fixme, I'm broken." tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; if (tmp < (unsigned long)&_end) tmp += PAGE_SIZE; diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c --- v2.3.47/linux/arch/mips/kernel/signal.c Tue Nov 23 22:42:20 1999 +++ linux/arch/mips/kernel/signal.c Thu Feb 24 22:52:30 2000 @@ -1,11 +1,12 @@ -/* $Id: signal.c,v 1.19 1999/06/17 13:25:47 ralf Exp $ +/* $Id: signal.c,v 1.25 2000/02/05 06:47:08 ralf Exp $ * - * linux/arch/mips/kernel/signal.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. * - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle - * - * XXX Handle lazy fp context switches correctly. + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1994 - 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. */ #include #include @@ -21,19 +22,20 @@ #include #include -#include +#include #include #include +#include #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, +extern asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); -asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); -extern asmlinkage void (*save_fp_context)(struct sigcontext *sc); -extern asmlinkage void (*restore_fp_context)(struct sigcontext *sc); +extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); +extern asmlinkage int save_fp_context(struct sigcontext *sc); +extern asmlinkage int restore_fp_context(struct sigcontext *sc); /* * Atomically swap in the new signal mask, and wait for a signal. @@ -52,6 +54,7 @@ spin_lock_irq(¤t->sigmask_lock); saveset = current->blocked; current->blocked = newset; + recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); regs.regs[2] = EINTR; @@ -67,17 +70,25 @@ asmlinkage int sys_rt_sigsuspend(struct pt_regs regs) { - sigset_t *uset, saveset, newset; + sigset_t *unewset, saveset, newset; + size_t sigsetsize; save_static(®s); - uset = (sigset_t *) regs.regs[4]; - if (copy_from_user(&newset, uset, sizeof(sigset_t))) + + /* XXX Don't preclude handling different sized sigset_t's. */ + sigsetsize = regs.regs[5]; + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + unewset = (sigset_t *) regs.regs[4]; + 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.regs[2] = EINTR; @@ -91,65 +102,74 @@ } asmlinkage int -sys_sigaction(int sig, const struct sigaction *act, - struct sigaction *oact) +sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) { struct k_sigaction new_ka, old_ka; int ret; + int err = 0; if (act) { - 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_flags, &act->sa_flags)) + old_sigset_t mask; + + if (!access_ok(VERIFY_READ, act, sizeof(*act))) + return -EFAULT; + err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); + err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + err |= __get_user(mask, &act->sa_mask.sig[0]); + err |= __get_user(new_ka.sa.sa_restorer, &act->sa_restorer); + if (err) return -EFAULT; - __copy_from_user(&mask, &act->sa_mask, sizeof(sigset_t)); - new_ka.ka_restorer = NULL; + 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_flags, &oact->sa_flags)) + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) + return -EFAULT; + err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); + err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); + err |= __put_user(0, &oact->sa_mask.sig[1]); + err |= __put_user(0, &oact->sa_mask.sig[2]); + err |= __put_user(0, &oact->sa_mask.sig[3]); + err |= __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer); + if (err) return -EFAULT; - __copy_to_user(&old_ka.sa.sa_mask, &oact->sa_mask, - sizeof(sigset_t)); } return ret; } asmlinkage int -sys_sigaltstack(const stack_t *uss, stack_t *uoss) +sys_sigaltstack(struct pt_regs regs) { - struct pt_regs *regs = (struct pt_regs *) &uss; + const stack_t *uss = (const stack_t *) regs.regs[4]; + stack_t *uoss = (stack_t *) regs.regs[5]; + unsigned long usp = regs.regs[29]; - return do_sigaltstack(uss, uoss, regs->regs[29]); + return do_sigaltstack(uss, uoss, usp); } -/* - * To do: this entire function should be accessed over a function pointer - * such that we can handle stack frames for different ABIs. - */ - -asmlinkage void -restore_sigcontext(struct pt_regs *regs, struct sigcontext *context) +asmlinkage int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { - long long reg; int owned_fp; + int err = 0; + u64 reg; - __get_user(regs->cp0_epc, &context->sc_pc); + err |= __get_user(regs->cp0_epc, &sc->sc_pc); - __get_user(reg, &context->sc_mdhi); + err |= __get_user(reg, &sc->sc_mdhi); regs->hi = (int) reg; - __get_user(reg, &context->sc_mdlo); + err |= __get_user(reg, &sc->sc_mdlo); regs->lo = (int) reg; -#define restore_gp_reg(i) __get_user(reg, &context->sc_regs[i]); \ - regs->regs[i] = (int) reg; +#define restore_gp_reg(i) do { \ + err |= __get_user(reg, &sc->sc_regs[i]); \ + regs->regs[i] = reg; \ +} 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); @@ -163,55 +183,40 @@ restore_gp_reg(31); #undef restore_gp_reg - /* FP depends on what FPU in what mode we have. */ - __get_user(owned_fp, &context->sc_ownedfp); -#if 0 + err |= __get_user(owned_fp, &sc->sc_ownedfp); if (owned_fp) { - restore_fp_context(context); + err |= restore_fp_context(sc); last_task_used_math = current; } -#endif -restore_fp_context(context); + + return err; } -/* - * The structure sc describes the stackframe on the userstack. The frames - * are identical for normal and realtime signal stackframes with the - * exception of the additional struct ucontext for rt frames. - */ struct sigframe { - unsigned long ass[4]; /* argument save space for o32 */ - unsigned int code[4]; /* signal trampoline */ - struct sigcontext scc; + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_code[2]; /* signal trampoline */ + struct sigcontext sf_sc; + sigset_t sf_mask; }; struct rt_sigframe { - unsigned long ass[4]; - unsigned int code[4]; - struct sigcontext scc; - // struct ucontext uc; + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_code[2]; /* signal trampoline */ + struct siginfo rs_info; + struct ucontext rs_uc; }; -asmlinkage int sys_sigreturn(struct pt_regs regs) +asmlinkage void +sys_sigreturn(struct pt_regs regs) { - struct sigcontext *context; + struct sigframe *frame; sigset_t blocked; - context = (struct sigcontext *)(long) regs.regs[29]; - if (!access_ok(VERIFY_READ, context, sizeof(struct sigcontext)) || - (regs.regs[29] & (SZREG - 1))) - goto badframe; - -#if 1 - if (__get_user(blocked.sig[0], &context->sc_sigset[0]) || - __get_user(blocked.sig[1], &context->sc_sigset[1]) || - __get_user(blocked.sig[2], &context->sc_sigset[2]) || - __get_user(blocked.sig[3], &context->sc_sigset[3])) + frame = (struct sigframe *) regs.regs[29]; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; -#else - if (__copy_from_user(&blocked, &context->sc_sigset, sizeof(blocked))) + if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) goto badframe; -#endif sigdelsetmask(&blocked, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); @@ -219,63 +224,79 @@ recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - restore_sigcontext(®s, context); + if (restore_sigcontext(®s, &frame->sf_sc)) + goto badframe; /* * Don't let your children do this ... */ __asm__ __volatile__( - "move\t$29,%0\n\t" + "move\t$29, %0\n\t" "j\tret_from_sys_call" :/* no outputs */ :"r" (®s)); /* Unreached */ badframe: - lock_kernel(); - do_exit(SIGSEGV); - unlock_kernel(); + force_sig(SIGSEGV, current); } -/* same as sys_sigreturn for now */ -asmlinkage int sys_rt_sigreturn(struct pt_regs regs) +asmlinkage void +sys_rt_sigreturn(struct pt_regs regs) { - return -ENOSYS; -} + struct rt_sigframe *frame; + sigset_t set; + stack_t st; -#define scc_offset ((size_t)&((struct sigframe *)0)->scc) + frame = (struct rt_sigframe *) regs.regs[29]; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) + goto badframe; -/* - * Set up the return code ... - * - * .set noreorder - * addiu sp,0x20 - * li v0,__NR_sigreturn - * syscall - * .set reorder - */ -static void inline -setup_trampoline(unsigned int *code) -{ - __put_user(0x27bd0000 + scc_offset , code + 0); - __put_user(0x24020000 + __NR_sigreturn, code + 1); - __put_user(0x0000000c , code + 2); + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + goto badframe; + + if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs.regs[29]); /* - * Flush caches so that the instructions will be correctly executed. + * Don't let your children do this ... */ - flush_cache_sigtramp((unsigned long) code); + __asm__ __volatile__( + "move\t$29, %0\n\t" + "j\tret_from_sys_call" + :/* no outputs */ + :"r" (®s)); + /* Unreached */ + +badframe: + force_sig(SIGSEGV, current); } -static void inline -setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc, sigset_t *set) +static int inline +setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { int owned_fp; + int err = 0; + u64 reg; - __put_user(regs->cp0_epc, &sc->sc_pc); - __put_user(regs->cp0_status, &sc->sc_status); /* Status register */ + err |= __put_user(regs->cp0_epc, &sc->sc_pc); + err |= __put_user(regs->cp0_status, &sc->sc_status); -#define save_gp_reg(i) __put_user(regs->regs[(i)], &sc->sc_regs[(i)]) +#define save_gp_reg(i) { \ + reg = regs->regs[i]; \ + err |= __put_user(reg, &sc->sc_regs[i]); \ +} while(0) __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); @@ -287,57 +308,93 @@ save_gp_reg(31); #undef save_gp_reg - __put_user(regs->hi, &sc->sc_mdhi); - __put_user(regs->lo, &sc->sc_mdlo); - __put_user(regs->cp0_cause, &sc->sc_cause); + err |= __put_user(regs->hi, &sc->sc_mdhi); + err |= __put_user(regs->lo, &sc->sc_mdlo); + err |= __put_user(regs->cp0_cause, &sc->sc_cause); + err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); owned_fp = (current == last_task_used_math); - __put_user(owned_fp, &sc->sc_ownedfp); + err |= __put_user(owned_fp, &sc->sc_ownedfp); -#if 0 if (current->used_math) { /* fp is active. */ set_cp0_status(ST0_CU1, ST0_CU1); - save_fp_context(sc); /* CPU-dependent */ + err |= save_fp_context(sc); last_task_used_math = NULL; regs->cp0_status &= ~ST0_CU1; current->used_math = 0; } -#endif -set_cp0_status(ST0_CU1, ST0_CU1); -save_fp_context(sc); /* CPU-dependent */ - __put_user(set->sig[0], &sc->sc_sigset[0]); - __put_user(set->sig[1], &sc->sc_sigset[1]); - __put_user(set->sig[2], &sc->sc_sigset[2]); - __put_user(set->sig[3], &sc->sc_sigset[3]); + return err; +} + +/* + * Determine which stack to use.. + */ +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +{ + unsigned long sp; + + /* Default to using normal stack */ + sp = regs->regs[29]; + + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void *)((sp - frame_size) & ALMASK); } static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs, - int signr, sigset_t *oldmask) + int signr, sigset_t *set) { struct sigframe *frame; - struct sigcontext *sc; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub already + in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) + regs->regs[31] = (unsigned long) ka->sa.sa_restorer; + else { + /* + * Set up the return code ... + * + * li v0, __NR_sigreturn + * syscall + */ + err |= __put_user(0x24020000 + __NR_sigreturn, + frame->sf_code + 0); + err |= __put_user(0x0000000c , + frame->sf_code + 1); + flush_cache_sigtramp((unsigned long) frame->sf_code); + } - /* Align the stackframe to an adequate boundary for the architecture. */ - frame = (struct sigframe *) (long) regs->regs[29]; - frame--; - frame = (struct sigframe *)((unsigned long)frame & ALMASK); - - if (verify_area(VERIFY_WRITE, frame, sizeof (*frame))) - goto segv_and_exit; - sc = &frame->scc; - - setup_trampoline(frame->code); - setup_sigcontext(regs, &frame->scc, oldmask); - - regs->regs[4] = signr; /* arguments */ - regs->regs[5] = 0; /* should be cause */ - regs->regs[6] = (long) frame; /* ptr to sigcontext */ - regs->regs[29] = (unsigned long) frame; /* Stack pointer */ - regs->regs[31] = (unsigned long) frame->code; /* Return address */ - regs->cp0_epc = (unsigned long) ka->sa.sa_handler; /* handler address */ - regs->regs[25] = regs->cp0_epc; /* PIC shit... */ + err |= setup_sigcontext(regs, &frame->sf_sc); + err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); + if (err) + goto give_sigsegv; + + /* + * Arguments to signal handler: + * + * a0 = signal number + * a1 = 0 (should be cause) + * a2 = pointer to struct sigcontext + * + * $25 and c0_epc point to the signal handler, $29 points to the + * struct sigframe. + */ + regs->regs[ 4] = signr; + regs->regs[ 5] = 0; + regs->regs[ 6] = (unsigned long) &frame->sf_sc; + regs->regs[29] = (unsigned long) frame; + regs->regs[31] = (unsigned long) frame->sf_code; + 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", @@ -345,22 +402,90 @@ #endif return; -segv_and_exit: - lock_kernel(); - do_exit(SIGSEGV); - unlock_kernel(); +give_sigsegv: + if (signr == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); } static void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, - int signr, sigset_t *oldmask, siginfo_t *info) + int signr, sigset_t *set, siginfo_t *info) { - printk("Aiee: setup_tr_frame wants to be written"); -} + struct rt_sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub already + in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) + regs->regs[31] = (unsigned long) ka->sa.sa_restorer; + else { + /* + * Set up the return code ... + * + * li v0, __NR_sigreturn + * syscall + */ + err |= __put_user(0x24020000 + __NR_sigreturn, + frame->rs_code + 0); + err |= __put_user(0x0000000c , + frame->rs_code + 1); + flush_cache_sigtramp((unsigned long) frame->rs_code); + } -/* ------------------------------------------------------------------------- */ + /* Create siginfo. */ + err |= __copy_to_user(&frame->rs_info, info, sizeof(*info)); -static inline void handle_signal(unsigned long sig, struct k_sigaction *ka, + /* Create the ucontext. */ + err |= __put_user(0, &frame->rs_uc.uc_flags); + err |= __put_user(0, &frame->rs_uc.uc_link); + err |= __put_user((void *)current->sas_ss_sp, + &frame->rs_uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->regs[29]), + &frame->rs_uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, + &frame->rs_uc.uc_stack.ss_size); + err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); + err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); + + if (err) + goto give_sigsegv; + + /* + * Arguments to signal handler: + * + * a0 = signal number + * a1 = 0 (should be cause) + * a2 = pointer to ucontext + * + * $25 and c0_epc point to the signal handler, $29 points to + * the struct rt_sigframe. + */ + regs->regs[ 4] = signr; + regs->regs[ 5] = (unsigned long) &frame->rs_info; + regs->regs[ 6] = (unsigned long) &frame->rs_uc; + regs->regs[29] = (unsigned long) frame; + regs->regs[31] = (unsigned long) frame->rs_code; + 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); +#endif + return; + +give_sigsegv: + if (signr == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static inline void +handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { if (ka->sa.sa_flags & SA_SIGINFO) @@ -379,7 +504,8 @@ } } -static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) +static inline void +syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) { switch(regs->regs[0]) { case ERESTARTNOHAND: @@ -407,7 +533,7 @@ siginfo_t info; #ifdef CONFIG_BINFMT_IRIX - if (current->personality != PER_LINUX) /* XXX */ + if (current->personality != PER_LINUX) return do_irix_signal(oldset, regs); #endif @@ -528,14 +654,4 @@ } } return 0; -} - -/* - * Compatibility syscall. Can be replaced in libc. - */ -asmlinkage int sys_pause(void) -{ - current->state = TASK_INTERRUPTIBLE; - schedule(); - return -ERESTARTNOHAND; } diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/syscall.c linux/arch/mips/kernel/syscall.c --- v2.3.47/linux/arch/mips/kernel/syscall.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/syscall.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: syscall.c,v 1.10 1999/02/15 02:16:52 ralf Exp $ +/* $Id: syscall.c,v 1.13 2000/02/04 07:40:23 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -55,64 +55,46 @@ return res; } -asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot, - int flags, int fd, off_t offset) +/* common code for old and new mmaps */ +static inline long +do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, unsigned long pgoff) { + int error = -EBADF; struct file * file = NULL; - unsigned long error = -EFAULT; - down(¤t->mm->mmap_sem); - lock_kernel(); + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); if (!(flags & MAP_ANONYMOUS)) { - error = -EBADF; file = fget(fd); if (!file) goto out; } - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - error = do_mmap(file, addr, len, prot, flags, offset); - if (file) - fput(file); -out: + + down(¤t->mm->mmap_sem); + lock_kernel(); + + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + unlock_kernel(); up(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: return error; } -asmlinkage int sys_idle(void) +asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot, + int flags, int fd, off_t offset) { - unsigned long start_idle = 0; - - if (current->pid != 0) - return -EPERM; - - /* endless idle loop with no priority at all */ - current->priority = 0; - current->counter = 0; - for (;;) { - /* - * R4[36]00 have wait, R4[04]00 don't. - * FIXME: We should save power by reducing the clock where - * possible. Thiss will cut down the power consuption - * of R4200 systems to about 1/16th of normal, the - * same for logic clocked with the processor generated - * clocks. - */ - if (!start_idle) { - check_pgt_cache(); - start_idle = jiffies; - } - if (wait_available && !current->need_resched) - __asm__(".set\tmips3\n\t" - "wait\n\t" - ".set\tmips0"); - run_task_queue(&tq_scheduler); - if (current->need_resched) - start_idle = 0; - schedule(); - } + return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); +} - return 0; +asmlinkage long +sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, unsigned long pgoff) +{ + return do_mmap2(addr, len, prot, flags, fd, pgoff); } asmlinkage int sys_fork(struct pt_regs regs) diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/syscalls.h linux/arch/mips/kernel/syscalls.h --- v2.3.47/linux/arch/mips/kernel/syscalls.h Wed Jul 28 10:30:10 1999 +++ linux/arch/mips/kernel/syscalls.h Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: syscalls.h,v 1.15 1998/09/19 19:16:17 ralf Exp $ +/* $Id: syscalls.h,v 1.22 2000/02/18 00:24:30 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -44,7 +44,7 @@ SYS(sys_ptrace, 4) SYS(sys_alarm, 1) SYS(sys_fstat, 2) -SYS(sys_pause, 0) +SYS(sys_ni_syscall, 0) SYS(sys_utime, 2) /* 4030 */ SYS(sys_ni_syscall, 0) SYS(sys_ni_syscall, 0) @@ -105,7 +105,7 @@ SYS(sys_swapon, 2) SYS(sys_reboot, 3) SYS(old_readdir, 3) -SYS(sys_mmap, 6) /* 4090 */ +SYS(old_mmap, 6) /* 4090 */ SYS(sys_munmap, 2) SYS(sys_truncate, 2) SYS(sys_ftruncate, 2) @@ -127,7 +127,7 @@ SYS(sys_uname, 1) SYS(sys_iopl, 0) /* Well, actually 17 args ... */ /* 4110 */ SYS(sys_vhangup, 0) -SYS(sys_idle, 0) +SYS(sys_ni_syscall, 0) /* was sys_idle() */ SYS(sys_vm86, 1) SYS(sys_wait4, 4) SYS(sys_swapoff, 1) /* 4115 */ @@ -214,14 +214,21 @@ SYS(sys_rt_sigpending, 2) SYS(sys_rt_sigtimedwait, 4) SYS(sys_rt_sigqueueinfo, 3) -SYS(sys_rt_sigsuspend, 2) -SYS(sys_pread, 4) /* 4200 */ -SYS(sys_pwrite, 4) +SYS(sys_rt_sigsuspend, 0) +SYS(sys_pread, 6) /* 4200 */ +SYS(sys_pwrite, 6) SYS(sys_chown, 3) SYS(sys_getcwd, 2) SYS(sys_capget, 2) SYS(sys_capset, 2) /* 4205 */ -SYS(sys_sigaltstack, 2) +SYS(sys_sigaltstack, 0) SYS(sys_sendfile, 3) SYS(sys_ni_syscall, 0) SYS(sys_ni_syscall, 0) +SYS(sys_mmap2, 6) /* 4210 */ +SYS(sys_truncate64, 2) +SYS(sys_ftruncate64, 2) +SYS(sys_stat64, 3) +SYS(sys_lstat64, 3) +SYS(sys_fstat64, 3) /* 4215 */ +SYS(sys_pivot_root, 2) diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c --- v2.3.47/linux/arch/mips/kernel/sysirix.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/sysirix.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: sysirix.c,v 1.20 1999/06/17 13:25:48 ralf Exp $ +/* $Id: sysirix.c,v 1.24 2000/02/05 06:47:08 ralf Exp $ * * sysirix.c: IRIX system call emulation. * @@ -27,13 +27,15 @@ #include #include -#include +#include #include #include #include /* 2,526 lines of complete and utter shit coming up... */ +extern int max_threads; + /* The sysmp commands supported thus far. */ #define MP_NPROCS 1 /* # processor in complex */ #define MP_NAPROCS 2 /* # active processors in complex */ @@ -45,7 +47,6 @@ int base = 0; int error = 0; - lock_kernel(); if(regs->regs[2] == 1000) base = 1; cmd = regs->regs[base + 4]; @@ -55,8 +56,7 @@ break; case MP_NPROCS: case MP_NAPROCS: - error = 1; - error = NR_CPUS; + error = smp_num_cpus; break; default: printk("SYSMP[%s:%ld]: Unsupported opcode %d\n", @@ -65,7 +65,6 @@ break; } - unlock_kernel(); return error; } @@ -100,7 +99,7 @@ case PR_MAXPROCS: printk("irix_prctl[%s:%ld]: Wants PR_MAXPROCS\n", current->comm, current->pid); - error = NR_TASKS; + error = max_threads; break; case PR_ISBLOCKED: { @@ -113,7 +112,7 @@ error = -ESRCH; break; } - error = (task->next_run ? 0 : 1); + error = (task->run_list.next != NULL); /* Can _your_ OS find this out that fast? */ break; } @@ -359,7 +358,7 @@ retval = (MAX_ARG_PAGES >> 4); /* XXX estimate... */ goto out; case 2: - retval = NR_TASKS; + retval = max_threads; goto out; case 3: retval = HZ; @@ -1104,26 +1103,27 @@ struct file *file = NULL; unsigned long retval; - down(¤t->mm->mmap_sem); lock_kernel(); - if(!(flags & MAP_ANONYMOUS)) { - if(!(file = fget(fd))) { + if (!(flags & MAP_ANONYMOUS)) { + if (!(file = fget(fd))) { retval = -EBADF; goto out; } - /* Ok, bad taste hack follows, try to think in something else when reading this */ - if (flags & IRIX_MAP_AUTOGROW){ + + /* Ok, bad taste hack follows, try to think in something else + * when reading this. */ + if (flags & IRIX_MAP_AUTOGROW) { unsigned long old_pos; long max_size = offset + len; - if (max_size > file->f_dentry->d_inode->i_size){ + if (max_size > file->f_dentry->d_inode->i_size) { old_pos = sys_lseek (fd, max_size - 1, 0); sys_write (fd, "", 1); sys_lseek (fd, old_pos, 0); } } } - + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); retval = do_mmap(file, addr, len, prot, flags, offset); @@ -1132,7 +1132,7 @@ out: unlock_kernel(); - up(¤t->mm->mmap_sem); + return retval; } @@ -1684,23 +1684,24 @@ return retval; } -extern asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot, - int flags, int fd, off_t offset); +extern asmlinkage unsigned long +sys_mmap(unsigned long addr, size_t len, int prot, int flags, int fd, + off_t offset); asmlinkage int irix_mmap64(struct pt_regs *regs) { int len, prot, flags, fd, off1, off2, error, base = 0; - unsigned long addr, *sp; - struct file *file; - + unsigned long addr, pgoff, *sp; + struct file *file = NULL; + lock_kernel(); - if(regs->regs[2] == 1000) + if (regs->regs[2] == 1000) base = 1; sp = (unsigned long *) (regs->regs[29] + 16); addr = regs->regs[base + 4]; len = regs->regs[base + 5]; prot = regs->regs[base + 6]; - if(!base) { + if (!base) { flags = regs->regs[base + 7]; error = verify_area(VERIFY_READ, sp, (4 * sizeof(unsigned long))); if(error) @@ -1717,63 +1718,72 @@ __get_user(off1, &sp[2]); __get_user(off2, &sp[3]); } - if(off1) { - error = -EINVAL; + + if (off1 & PAGE_MASK) { + error = -EOVERFLOW; goto out; } - if(!(flags & MAP_ANONYMOUS)) { - if(!(file = fcheck(fd))) { + pgoff = (off1 << (32 - PAGE_SHIFT)) | (off2 >> PAGE_SHIFT); + + if (!(flags & MAP_ANONYMOUS)) { + if (!(file = fcheck(fd))) { error = -EBADF; goto out; } - - /* Ok, bad taste hack follows, try to think in something else when reading this */ - if (flags & IRIX_MAP_AUTOGROW){ + + /* Ok, bad taste hack follows, try to think in something else + when reading this */ + if (flags & IRIX_MAP_AUTOGROW) { unsigned long old_pos; long max_size = off2 + len; - - if (max_size > file->f_dentry->d_inode->i_size){ + + if (max_size > file->f_dentry->d_inode->i_size) { old_pos = sys_lseek (fd, max_size - 1, 0); sys_write (fd, "", 1); sys_lseek (fd, old_pos, 0); } } } - - error = sys_mmap(addr, (size_t) len, prot, flags, fd, off2); + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + down(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up(¤t->mm->mmap_sem); + + if (file) + fput(file); out: unlock_kernel(); + return error; } asmlinkage int irix_dmi(struct pt_regs *regs) { - lock_kernel(); printk("[%s:%ld] Wheee.. irix_dmi()\n", current->comm, current->pid); - unlock_kernel(); + return -EINVAL; } asmlinkage int irix_pread(int fd, char *buf, int cnt, int off64, int off1, int off2) { - lock_kernel(); printk("[%s:%ld] Wheee.. irix_pread(%d,%p,%d,%d,%d,%d)\n", current->comm, current->pid, fd, buf, cnt, off64, off1, off2); - unlock_kernel(); + return -EINVAL; } asmlinkage int irix_pwrite(int fd, char *buf, int cnt, int off64, int off1, int off2) { - lock_kernel(); printk("[%s:%ld] Wheee.. irix_pwrite(%d,%p,%d,%d,%d,%d)\n", current->comm, current->pid, fd, buf, cnt, off64, off1, off2); - unlock_kernel(); + return -EINVAL; } @@ -1781,12 +1791,11 @@ unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { - lock_kernel(); printk("[%s:%ld] Wheee.. irix_fastpath(%d,%08lx,%08lx,%08lx,%08lx," "%08lx,%08lx)\n", current->comm, current->pid, cmd, arg0, arg1, arg2, arg3, arg4, arg5); - unlock_kernel(); + return -EINVAL; } @@ -2414,12 +2423,10 @@ asmlinkage int irix_unimp(struct pt_regs *regs) { - lock_kernel(); printk("irix_unimp [%s:%ld] v0=%d v1=%d a0=%08lx a1=%08lx a2=%08lx " "a3=%08lx\n", current->comm, current->pid, (int) regs->regs[2], (int) regs->regs[3], regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]); - unlock_kernel(); return -ENOSYS; } diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/sysmips.c linux/arch/mips/kernel/sysmips.c --- v2.3.47/linux/arch/mips/kernel/sysmips.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/sysmips.c Thu Feb 24 22:52:30 2000 @@ -7,7 +7,7 @@ * * Copyright (C) 1995, 1996, 1997 by Ralf Baechle * - * $Id: sysmips.c,v 1.6 1998/08/25 09:14:42 ralf Exp $ + * $Id: sysmips.c,v 1.9 2000/02/18 00:24:30 ralf Exp $ */ #include #include @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include @@ -72,6 +72,7 @@ if (len == 0 || len > __NEW_UTS_LEN) goto out; + /* Fiiiixmeeee... */ copy_from_user(system_utsname.nodename, name, len); system_utsname.nodename[len] = '\0'; retval = 0; @@ -91,8 +92,8 @@ goto out; case MIPS_FIXADE: - tmp = current->tss.mflags & ~3; - current->tss.mflags = tmp | (arg1 & 3); + tmp = current->thread.mflags & ~3; + current->thread.mflags = tmp | (arg1 & 3); retval = 0; goto out; diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/time.c linux/arch/mips/kernel/time.c --- v2.3.47/linux/arch/mips/kernel/time.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/kernel/time.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.12 1999/06/13 16:30:34 ralf Exp $ +/* $Id: time.c,v 1.14 2000/01/26 00:07:44 ralf Exp $ * * Copyright (C) 1991, 1992, 1995 Linus Torvalds * Copyright (C) 1996, 1997, 1998 Ralf Baechle @@ -6,7 +6,6 @@ * This file contains the time handling details for PC-style clocks as * found in some MIPS systems. */ -#include #include #include #include @@ -20,6 +19,7 @@ #include #include #include +#include #include #include @@ -336,6 +336,24 @@ static void inline timer_interrupt(int irq, void *dev_id, struct pt_regs * regs) { +#ifdef CONFIG_DDB5074 + static unsigned cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) + ddb5074_led_d2(1); + else if (cnt == 7 || cnt == dist+7) + ddb5074_led_d2(0); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672<pid) { diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c --- v2.3.47/linux/arch/mips/kernel/traps.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/kernel/traps.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.20 1999/06/13 16:30:34 ralf Exp $ +/* $Id: traps.c,v 1.27 2000/01/16 01:29:05 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,11 +25,19 @@ #include #include #include +#include + +extern int console_loglevel; + +static inline void console_silent(void) +{ + console_loglevel = 0; +} static inline void console_verbose(void) { - extern int console_loglevel; - console_loglevel = 15; + if (console_loglevel) + console_loglevel = 15; } /* @@ -40,12 +49,9 @@ extern asmlinkage void deskstation_tyne_handle_int(void); extern asmlinkage void mips_magnum_4000_handle_int(void); -extern asmlinkage void r4k_handle_mod(void); -extern asmlinkage void r2300_handle_mod(void); -extern asmlinkage void r4k_handle_tlbl(void); -extern asmlinkage void r2300_handle_tlbl(void); -extern asmlinkage void r4k_handle_tlbs(void); -extern asmlinkage void r2300_handle_tlbs(void); +extern asmlinkage void handle_mod(void); +extern asmlinkage void handle_tlbl(void); +extern asmlinkage void handle_tlbs(void); extern asmlinkage void handle_adel(void); extern asmlinkage void handle_ades(void); extern asmlinkage void handle_ibe(void); @@ -77,6 +83,23 @@ */ #define MODULE_RANGE (8*1024*1024) +#if !defined(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 +#define RT 0x001f0000 +#define OFFSET 0x0000ffff +#define LL 0xc0000000 +#define SC 0xd0000000 + +#define DEBUG_LLSC +#endif + /* * This routine abuses get_user()/put_user() to reference pointers * with at least a bit of error checking ... @@ -173,13 +196,17 @@ } } -void die(const char * str, struct pt_regs * regs, unsigned long err) -{ - if (user_mode(regs)) /* Just return if in user mode. */ - return; +spinlock_t die_lock; +extern void __die(const char * str, struct pt_regs * regs, const char *where, + unsigned long line) +{ console_verbose(); - printk("%s: %04lx\n", str, err & 0xffff); + 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: %ld, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long) current); @@ -187,13 +214,16 @@ show_trace((unsigned int *) regs->regs[29]); show_code((unsigned int *) regs->cp0_epc); printk("\n"); +while(1); + spin_unlock_irq(&die_lock); 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, const char *where, + unsigned long line) { if (!user_mode(regs)) - die(str, regs, err); + __die(str, regs, where, line); } static void default_be_board_handler(struct pt_regs *regs) @@ -201,8 +231,10 @@ /* * Assume it would be too dangerous to continue ... */ - force_sig(SIGBUS, current); +/* XXX */ +printk("Got Bus Error at %08x\n", (unsigned int)regs->cp0_epc); show_regs(regs); while(1); + force_sig(SIGBUS, current); } void do_ibe(struct pt_regs *regs) @@ -249,6 +281,7 @@ { unsigned long pc; unsigned int insn; + extern void simfp(void*); #ifdef CONFIG_MIPS_FPE_MODULE if (fpe_handler != NULL) { @@ -307,7 +340,6 @@ return 0; } - void do_bp(struct pt_regs *regs) { unsigned int opcode, bcode; @@ -340,11 +372,115 @@ /* * (A short test says that IRIX 5.3 sends SIGTRAP for all break * insns, even for break codes that indicate arithmetic failures. - * Wiered ...) + * Weird ...) */ force_sig(SIGTRAP, current); } +#if !defined(CONFIG_CPU_HAS_LLSC) + +/* + * userland emulation for R2300 CPUs + * needed for the multithreading part of glibc + */ +void do_ri(struct pt_regs *regs) +{ + unsigned int opcode; + + lock_kernel(); + if (!get_insn_opcode(regs, &opcode)) { + if ((opcode & OPCODE) == LL) + simulate_ll(regs, opcode); + if ((opcode & OPCODE) == SC) + simulate_sc(regs, opcode); + } else { + printk("[%s:%ld] Illegal instruction at %08lx ra=%08lx\n", + current->comm, current->pid, regs->cp0_epc, regs->regs[31]); + } + unlock_kernel(); + if (compute_return_epc(regs)) + return; + force_sig(SIGILL, current); +} + +/* + * the ll_bit will be cleared by r2300_switch.S + */ +unsigned long ll_bit, *lladdr; + +void simulate_ll(struct pt_regs *regp, unsigned int opcode) +{ + unsigned long *addr, *vaddr; + long offset; + + /* + * analyse the ll instruction that just caused a ri exception + * and put the referenced address to addr. + */ + /* sign extend offset */ + offset = opcode & OFFSET; + if (offset & 0x00008000) + offset = -(offset & 0x00007fff); + else + offset = (offset & 0x00007fff); + + vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset); + +#ifdef DEBUG_LLSC + printk("ll: vaddr = 0x%08x, reg = %d\n", (unsigned int)vaddr, (opcode & RT) >> 16); +#endif + + /* + * TODO: compute physical address from vaddr + */ + panic("ll: emulation not yet finished!"); + + lladdr = addr; + ll_bit = 1; + regp->regs[(opcode & RT) >> 16] = *addr; +} + +void simulate_sc(struct pt_regs *regp, unsigned int opcode) +{ + unsigned long *addr, *vaddr, reg; + long offset; + + /* + * analyse the sc instruction that just caused a ri exception + * and put the referenced address to addr. + */ + /* sign extend offset */ + offset = opcode & OFFSET; + if (offset & 0x00008000) + offset = -(offset & 0x00007fff); + else + offset = (offset & 0x00007fff); + + vaddr = (unsigned long *)((long)(regp->regs[(opcode & BASE) >> 21]) + offset); + reg = (opcode & RT) >> 16; + +#ifdef DEBUG_LLSC + printk("sc: vaddr = 0x%08x, reg = %d\n", (unsigned int)vaddr, (unsigned int)reg); +#endif + + /* + * TODO: compute physical address from vaddr + */ + panic("sc: emulation not yet finished!"); + + lladdr = addr; + + if (ll_bit == 0) { + regp->regs[reg] = 0; + return; + } + + *addr = regp->regs[reg]; + regp->regs[reg] = 1; +} + +#else /* MIPS 2 or higher */ + void do_ri(struct pt_regs *regs) { lock_kernel(); @@ -356,9 +492,13 @@ force_sig(SIGILL, current); } +#endif + void do_cpu(struct pt_regs *regs) { unsigned int cpid; + extern void lazy_fpu_switch(void*); + extern void init_fpu(void); cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; if (cpid != 1) @@ -369,10 +509,10 @@ return; if (current->used_math) { /* Using the FPU again. */ - r4xx0_lazy_fpu_switch(last_task_used_math); + lazy_fpu_switch(last_task_used_math); } else { /* First time FPU user. */ - r4xx0_init_fpu(); + init_fpu(); current->used_math = 1; } last_task_used_math = current; @@ -454,19 +594,6 @@ } } -asmlinkage void (*save_fp_context)(struct sigcontext *sc); -extern asmlinkage void r4k_save_fp_context(struct sigcontext *sc); -extern asmlinkage void r2300_save_fp_context(struct sigcontext *sc); -extern asmlinkage void r6000_save_fp_context(struct sigcontext *sc); - -asmlinkage void (*restore_fp_context)(struct sigcontext *sc); -extern asmlinkage void r4k_restore_fp_context(struct sigcontext *sc); -extern asmlinkage void r2300_restore_fp_context(struct sigcontext *sc); -extern asmlinkage void r6000_restore_fp_context(struct sigcontext *sc); - -extern asmlinkage void *r4xx0_resume(void *last, void *next); -extern asmlinkage void *r2300_resume(void *last, void *next); - void __init trap_init(void) { extern char except_vec0_nevada, except_vec0_r4000; @@ -479,6 +606,9 @@ mips_machtype == MACH_SNI_RM200_PCI) EISA_bus = 1; + /* Some firmware leaves the BEV flag set, clear it. */ + set_cp0_status(ST0_BEV, 0); + /* 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); @@ -497,6 +627,29 @@ watch_init(mips_cputype); setup_dedicated_int(); + set_except_vector(1, handle_mod); + set_except_vector(2, handle_tlbl); + set_except_vector(3, handle_tlbs); + set_except_vector(4, handle_adel); + set_except_vector(5, handle_ades); + /* + * The Data Bus Error/ Instruction Bus Errors are signaled + * by external hardware. Therefore these two expection have + * board specific handlers. + */ + set_except_vector(6, handle_ibe); + set_except_vector(7, handle_dbe); + ibe_board_handler = default_be_board_handler; + dbe_board_handler = default_be_board_handler; + + set_except_vector(8, handle_sys); + set_except_vector(9, handle_bp); + set_except_vector(10, handle_ri); + set_except_vector(11, handle_cpu); + set_except_vector(12, handle_ov); + set_except_vector(13, handle_tr); + set_except_vector(15, handle_fpe); + /* * Handling the following exceptions depends mostly of the cpu type */ @@ -540,42 +693,16 @@ if (vce_available) { memcpy((void *)(KSEG0 + 0x180), &except_vec3_r4000, - 0x180); + 0x80); } else { memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, - 0x100); + 0x80); } - save_fp_context = r4k_save_fp_context; - restore_fp_context = r4k_restore_fp_context; - resume = r4xx0_resume; - set_except_vector(1, r4k_handle_mod); - set_except_vector(2, r4k_handle_tlbl); - set_except_vector(3, r4k_handle_tlbs); - set_except_vector(4, handle_adel); - set_except_vector(5, handle_ades); - - /* - * The following two are signaled by onboard hardware and - * should get board specific handlers to get maximum - * available information. - */ - set_except_vector(6, handle_ibe); - set_except_vector(7, handle_dbe); - - set_except_vector(8, handle_sys); - set_except_vector(9, handle_bp); - set_except_vector(10, handle_ri); - set_except_vector(11, handle_cpu); - set_except_vector(12, handle_ov); - set_except_vector(13, handle_tr); - set_except_vector(15, handle_fpe); break; case CPU_R6000: case CPU_R6000A: - save_fp_context = r6000_save_fp_context; - restore_fp_context = r6000_restore_fp_context; #if 0 /* * The R6000 is the only R-series CPU that features a machine @@ -592,31 +719,7 @@ case CPU_R3000: case CPU_R3000A: memcpy((void *)KSEG0, &except_vec0_r2300, 0x80); - save_fp_context = r2300_save_fp_context; - restore_fp_context = r2300_restore_fp_context; - resume = r2300_resume; - set_except_vector(1, r2300_handle_mod); - set_except_vector(2, r2300_handle_tlbl); - set_except_vector(3, r2300_handle_tlbs); - set_except_vector(4, handle_adel); - set_except_vector(5, handle_ades); - /* - * The Data Bus Error/ Instruction Bus Errors are signaled - * by external hardware. Therefore these two expection have - * board specific handlers. - */ - set_except_vector(6, handle_ibe); - set_except_vector(7, handle_dbe); - ibe_board_handler = default_be_board_handler; - dbe_board_handler = default_be_board_handler; - - set_except_vector(8, handle_sys); - set_except_vector(9, handle_bp); - set_except_vector(10, handle_ri); - set_except_vector(11, handle_cpu); - set_except_vector(12, handle_ov); - set_except_vector(13, handle_tr); - set_except_vector(15, handle_fpe); + memcpy((void *)(KSEG0 + 0x80), &except_vec3_generic, 0x80); break; case CPU_R3041: case CPU_R3051: @@ -634,4 +737,8 @@ panic("Unknown CPU type"); } flush_icache_range(KSEG0, KSEG0 + 0x200); + + atomic_inc(&init_mm.mm_count); /* XXX UP? */ + current->active_mm = &init_mm; + current_pgd = init_mm.pgd; } diff -u --recursive --new-file v2.3.47/linux/arch/mips/kernel/unaligned.c linux/arch/mips/kernel/unaligned.c --- v2.3.47/linux/arch/mips/kernel/unaligned.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/kernel/unaligned.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,5 @@ -/* +/* $Id: unaligned.c,v 1.7 1999/12/04 03:59:00 ralf Exp $ + * * Handle unaligned accesses by emulation. * * This file is subject to the terms and conditions of the GNU General Public @@ -7,7 +8,7 @@ * * Copyright (C) 1996, 1998 by Ralf Baechle * - * $Id: unaligned.c,v 1.5 1999/05/01 22:40:39 ralf Exp $ + * $Id: unaligned.c,v 1.7 1999/12/04 03:59:00 ralf Exp $ * * This file contains exception handler for address error exception with the * special capability to execute faulting instructions in software. The @@ -365,19 +366,13 @@ return; } - lock_kernel(); send_sig(SIGSEGV, current, 1); - unlock_kernel(); return; sigbus: - lock_kernel(); send_sig(SIGBUS, current, 1); - unlock_kernel(); return; sigill: - lock_kernel(); send_sig(SIGILL, current, 1); - unlock_kernel(); return; } @@ -398,7 +393,7 @@ pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0); if (compute_return_epc(regs)) return; - if ((current->tss.mflags & MF_FIXADE) == 0) + if ((current->thread.mflags & MF_FIXADE) == 0) goto sigbus; emulate_load_store_insn(regs, regs->cp0_badvaddr, pc); @@ -407,9 +402,7 @@ return; sigbus: - lock_kernel(); force_sig(SIGBUS, current); - unlock_kernel(); return; } diff -u --recursive --new-file v2.3.47/linux/arch/mips/ld.script.big linux/arch/mips/ld.script.big --- v2.3.47/linux/arch/mips/ld.script.big Fri May 8 00:13:24 1998 +++ linux/arch/mips/ld.script.big Thu Feb 24 22:52:30 2000 @@ -5,26 +5,6 @@ { /* Read-only sections, merged into text segment: */ . = 0x80000000; - .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.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } .init : { *(.init) } =0 .text : { @@ -38,14 +18,30 @@ _etext = .; PROVIDE (etext = .); + . = ALIGN(8192); + .data.init_task : { *(.data.init_task) } + /* Startup code */ . = ALIGN(4096); __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(4096); /* Align double page for init_task_union */ __init_end = .; + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + .fini : { *(.fini) } =0 .reginfo : { *(.reginfo) } /* Adjust the address for the data segment. We want to adjust up to @@ -86,6 +82,7 @@ __bss_start = .; _fbss = .; + .sbss : { *(.sbss) *(.scommon) } .bss : { *(.dynbss) @@ -93,8 +90,6 @@ *(COMMON) _end = . ; PROVIDE (end = .); - *(.sbss) - *(.scommon) } /* These are needed for ELF backends which have not yet been converted to the new style linker. */ diff -u --recursive --new-file v2.3.47/linux/arch/mips/ld.script.little linux/arch/mips/ld.script.little --- v2.3.47/linux/arch/mips/ld.script.little Fri May 8 00:13:24 1998 +++ linux/arch/mips/ld.script.little Thu Feb 24 22:52:30 2000 @@ -5,26 +5,6 @@ { /* Read-only sections, merged into text segment: */ . = 0x80000000; - .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.init : { *(.rel.init) } - .rela.init : { *(.rela.init) } - .rel.fini : { *(.rel.fini) } - .rela.fini : { *(.rela.fini) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } .init : { *(.init) } =0 .text : { @@ -38,14 +18,30 @@ _etext = .; PROVIDE (etext = .); + . = ALIGN(8192); + .data.init_task : { *(.data.init_task) } + /* Startup code */ . = ALIGN(4096); __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(4096); /* Align double page for init_task_union */ __init_end = .; + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + .fini : { *(.fini) } =0 .reginfo : { *(.reginfo) } /* Adjust the address for the data segment. We want to adjust up to @@ -86,6 +82,7 @@ __bss_start = .; _fbss = .; + .sbss : { *(.sbss) *(.scommon) } .bss : { *(.dynbss) @@ -93,8 +90,6 @@ *(COMMON) _end = . ; PROVIDE (end = .); - *(.sbss) - *(.scommon) } /* These are needed for ELF backends which have not yet been converted to the new style linker. */ diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/Makefile linux/arch/mips/lib/Makefile --- v2.3.47/linux/arch/mips/lib/Makefile Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/lib/Makefile Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.9 1999/01/04 16:03:50 ralf Exp $ +# $Id: Makefile,v 1.12 1999/12/04 03:59:00 ralf Exp $ # # Makefile for MIPS-specific library files.. # @@ -9,8 +9,15 @@ $(CC) $(CFLAGS) -c $< -o $*.o L_TARGET = lib.a -L_OBJS = csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \ +L_OBJS = csum_partial.o csum_partial_copy.o floppy-std.o \ floppy-no.o ide-std.o ide-no.o kbd-std.o kbd-no.o rtc-std.o \ - rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o watch.o + rtc-no.o memcpy.o memset.o strlen_user.o strncpy_user.o \ + strnlen_user.o watch.o + +ifdef CONFIG_CPU_R3000 + L_OBJS += r3k_dump_tlb.o +else + L_OBJS += dump_tlb.o +endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/csum_partial_copy.c linux/arch/mips/lib/csum_partial_copy.c --- v2.3.47/linux/arch/mips/lib/csum_partial_copy.c Fri Jun 25 17:40:12 1999 +++ linux/arch/mips/lib/csum_partial_copy.c Thu Feb 24 22:52:30 2000 @@ -14,7 +14,7 @@ * 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 $ + * $Id: csum_partial_copy.c,v 1.3 2000/02/05 06:47:08 ralf Exp $ */ #include #include @@ -55,21 +55,4 @@ } return csum_partial(dst, len, sum); -} - -/* - * Copy to userspace and compute checksum. - */ -unsigned int csum_partial_copy_to_user (const char *src, char *dst, - int len, unsigned int sum, - int *err_ptr) -{ - sum = csum_partial(src, len, sum); - - if (copy_to_user(dst, src, len)) { - *err_ptr = -EFAULT; - return sum; - } - - return sum; } diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/dump_tlb.c linux/arch/mips/lib/dump_tlb.c --- v2.3.47/linux/arch/mips/lib/dump_tlb.c Fri May 8 00:13:24 1998 +++ linux/arch/mips/lib/dump_tlb.c Thu Feb 24 22:52:30 2000 @@ -1,8 +1,8 @@ /* * Dump R4x00 TLB for debugging purposes. * - * Copyright (C) 1994, 1995 by Waldorf Electronics, - * written by Ralf Baechle. + * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle. + * Copyright (C) 1999 by Silicon Graphics, Inc. */ #include #include @@ -11,27 +11,22 @@ #include #include -#include #include #include #include -static char *region_map [] = { - "u", "s", "k", "!" -}; +#define mips_tlb_entries 48 void dump_tlb(int first, int last) { int i; - int wired; - unsigned int pagemask, c0, c1, r; - unsigned long long entryhi, entrylo0, entrylo1; + unsigned int pagemask, c0, c1, asid; + unsigned long entryhi, entrylo0, entrylo1; - wired = read_32bit_cp0_register(CP0_WIRED); - printk("Wired: %d", wired); - - for(i=first;i> 62; c0 = (entrylo0 >> 3) & 7; c1 = (entrylo1 >> 3) & 7; - printk("%s vpn2=%08Lx " - "[pfn=%06Lx c=%d d=%d v=%d g=%Ld]" - "[pfn=%06Lx c=%d d=%d v=%d g=%Ld]", - region_map [r], (entryhi >> 13) & 0xffffffff, - (entrylo0 >> 6) & 0xffffff, c0, + 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, (entrylo0 & 4) ? 1 : 0, (entrylo0 & 2) ? 1 : 0, (entrylo0 & 1), - (entrylo1 >> 6) & 0xffffff, c1, + entrylo1 & PAGE_MASK, c1, (entrylo1 & 4) ? 1 : 0, (entrylo1 & 2) ? 1 : 0, (entrylo1 & 1)); @@ -74,6 +70,8 @@ } } printk("\n"); + + set_entryhi(asid); } void @@ -85,9 +83,45 @@ void dump_tlb_wired(void) { + int wired; + + wired = read_32bit_cp0_register(CP0_WIRED); + printk("Wired: %d", wired); dump_tlb(0, read_32bit_cp0_register(CP0_WIRED)); } +#define BARRIER \ + __asm__ __volatile__( \ + ".set\tnoreorder\n\t" \ + "nop;nop;nop;nop;nop;nop;nop\n\t" \ + ".set\treorder"); + +void +dump_tlb_addr(unsigned long addr) +{ + unsigned int flags, oldpid; + int index; + + __save_and_cli(flags); + oldpid = get_entryhi() & 0xff; + BARRIER; + set_entryhi((addr & PAGE_MASK) | oldpid); + BARRIER; + tlb_probe(); + BARRIER; + index = get_index(); + set_entryhi(oldpid); + __restore_flags(flags); + + if (index < 0) { + printk("No entry for address 0x%08lx in TLB\n", addr); + return; + } + + printk("Entry %d maps address 0x%08lx\n", index, addr); + dump_tlb(index, index); +} + void dump_tlb_nonwired(void) { @@ -101,12 +135,12 @@ pmd_t *pmd; pte_t *pte, page; unsigned int addr; + unsigned long val; addr = (unsigned int) address; - printk("Addr == %08x\n", addr); - printk("tasks->tss.pg_dir == %08x\n", (unsigned int) t->tss.pg_dir); - printk("tasks->mm.pgd == %08x\n", (unsigned int) t->mm->pgd); + printk("Addr == %08x\n", addr); + printk("tasks->mm.pgd == %08x\n", (unsigned int) t->mm->pgd); page_dir = pgd_offset(t->mm, 0); printk("page_dir == %08x\n", (unsigned int) page_dir); @@ -122,6 +156,17 @@ page = *pte; printk("page == %08x\n", (unsigned int) pte_val(page)); + + val = pte_val(page); + if (val & _PAGE_PRESENT) printk("present "); + if (val & _PAGE_READ) printk("read "); + if (val & _PAGE_WRITE) printk("write "); + if (val & _PAGE_ACCESSED) printk("accessed "); + if (val & _PAGE_MODIFIED) printk("modified "); + if (val & _PAGE_R4KBUG) printk("r4kbug "); + if (val & _PAGE_GLOBAL) printk("global "); + if (val & _PAGE_VALID) printk("valid "); + printk("\n"); } void diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/floppy-no.c linux/arch/mips/lib/floppy-no.c --- v2.3.47/linux/arch/mips/lib/floppy-no.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/floppy-no.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: floppy-no.c,v 1.1 1998/05/07 18:38:32 ralf Exp $ +/* $Id: floppy-no.c,v 1.1 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 diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/floppy-std.c linux/arch/mips/lib/floppy-std.c --- v2.3.47/linux/arch/mips/lib/floppy-std.c Wed Feb 16 17:03:51 2000 +++ linux/arch/mips/lib/floppy-std.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: floppy-std.c,v 1.3 1998/10/28 12:38:13 ralf Exp $ +/* $Id: floppy-std.c,v 1.3 2000/02/24 00:12:40 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 diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/kbd-no.c linux/arch/mips/lib/kbd-no.c --- v2.3.47/linux/arch/mips/lib/kbd-no.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/lib/kbd-no.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: kbd-no.c,v 1.1 1998/10/28 12:38:14 ralf Exp $ +/* $Id: kbd-no.c,v 1.1 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 diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/kbd-std.c linux/arch/mips/lib/kbd-std.c --- v2.3.47/linux/arch/mips/lib/kbd-std.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/lib/kbd-std.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: kbd-std.c,v 1.2 1999/06/11 14:29:45 ralf Exp $ +/* $Id: kbd-std.c,v 1.2 1999/06/17 13:25:50 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 diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/memcpy.S linux/arch/mips/lib/memcpy.S --- v2.3.47/linux/arch/mips/lib/memcpy.S Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/lib/memcpy.S Thu Feb 24 22:52:30 2000 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * $Id: memcpy.S,v 1.3 1998/07/10 01:14:49 ralf Exp $ + * $Id: memcpy.S,v 1.4 2000/01/27 01:05:23 ralf Exp $ * * Unified implementation of memcpy, memmove and the __copy_user backend. * For __rmemcpy and memmove an exception is always a kernel bug, therefore @@ -688,8 +688,8 @@ jr ra move a2, zero - END(__rmemcpy) #endif /* Horror fix */ + END(__rmemcpy) l_fixup: # clear the rest of the buffer lw t0, THREAD_BUADDR($28) diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/r3k_dump_tlb.c linux/arch/mips/lib/r3k_dump_tlb.c --- v2.3.47/linux/arch/mips/lib/r3k_dump_tlb.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/lib/r3k_dump_tlb.c Thu Feb 24 22:52:30 2000 @@ -0,0 +1,185 @@ +/* + * Dump R3000 TLB for debugging purposes. + * + * Copyright (C) 1994, 1995 by Waldorf Electronics, written by Ralf Baechle. + * Copyright (C) 1999 by Silicon Graphics, Inc. + * Copyright (C) 1999 by Harald Koerfgen + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define mips_tlb_entries 64 + +void +dump_tlb(int first, int last) +{ + int i; + unsigned int asid; + unsigned long entryhi, entrylo0; + + asid = get_entryhi() & 0xfc0; + + for(i=first;i<=last;i++) + { + write_32bit_cp0_register(CP0_INDEX, i); + __asm__ __volatile__( + ".set\tnoreorder\n\t" + "tlbr\n\t" + "nop\n\t" + ".set\treorder"); + entryhi = read_32bit_cp0_register(CP0_ENTRYHI); + entrylo0 = read_32bit_cp0_register(CP0_ENTRYLO0); + + /* Unused entries have a virtual address of KSEG0. */ + if ((entryhi & 0xffffe000) != 0x80000000 + && (entryhi & 0xfc0) == asid) { + /* + * Only print entries in use + */ + printk("Index: %2d ", i); + + printk("va=%08lx asid=%08lx" + " [pa=%06lx n=%d d=%d v=%d g=%ld]", + (entryhi & 0xffffe000), + entryhi & 0xfc0, + entrylo0 & PAGE_MASK, + (entrylo0 & (1 << 11)) ? 1 : 0, + (entrylo0 & (1 << 10)) ? 1 : 0, + (entrylo0 & (1 << 9)) ? 1 : 0, + (entrylo0 & (1 << 8)) ? 1 : 0); + } + } + printk("\n"); + + set_entryhi(asid); +} + +void +dump_tlb_all(void) +{ + dump_tlb(0, mips_tlb_entries - 1); +} + +void +dump_tlb_wired(void) +{ + int wired = 7; + + printk("Wired: %d", wired); + dump_tlb(0, read_32bit_cp0_register(CP0_WIRED)); +} + +void +dump_tlb_addr(unsigned long addr) +{ + unsigned int flags, oldpid; + int index; + + __save_and_cli(flags); + oldpid = get_entryhi() & 0xff; + set_entryhi((addr & PAGE_MASK) | oldpid); + tlb_probe(); + index = get_index(); + set_entryhi(oldpid); + __restore_flags(flags); + + if (index < 0) { + printk("No entry for address 0x%08lx in TLB\n", addr); + return; + } + + printk("Entry %d maps address 0x%08lx\n", index, addr); + dump_tlb(index, index); +} + +void +dump_tlb_nonwired(void) +{ + dump_tlb(8, mips_tlb_entries - 1); +} + +void +dump_list_process(struct task_struct *t, void *address) +{ + pgd_t *page_dir, *pgd; + pmd_t *pmd; + pte_t *pte, page; + unsigned int addr; + unsigned long val; + + 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("page_dir == %08x\n", (unsigned int) page_dir); + + pgd = pgd_offset(t->mm, addr); + printk("pgd == %08x, ", (unsigned int) pgd); + + pmd = pmd_offset(pgd, addr); + printk("pmd == %08x, ", (unsigned int) pmd); + + pte = pte_offset(pmd, addr); + printk("pte == %08x, ", (unsigned int) pte); + + page = *pte; + printk("page == %08x\n", (unsigned int) pte_val(page)); + + val = pte_val(page); + if (val & _PAGE_PRESENT) printk("present "); + if (val & _PAGE_READ) printk("read "); + if (val & _PAGE_WRITE) printk("write "); + if (val & _PAGE_ACCESSED) printk("accessed "); + if (val & _PAGE_MODIFIED) printk("modified "); + if (val & _PAGE_GLOBAL) printk("global "); + if (val & _PAGE_VALID) printk("valid "); + printk("\n"); +} + +void +dump_list_current(void *address) +{ + dump_list_process(current, address); +} + +unsigned int +vtop(void *address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned int addr, paddr; + + addr = (unsigned long) address; + pgd = pgd_offset(current->mm, addr); + pmd = pmd_offset(pgd, addr); + pte = pte_offset(pmd, addr); + paddr = (KSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK; + paddr |= (addr & ~PAGE_MASK); + + return paddr; +} + +void +dump16(unsigned long *p) +{ + int i; + + for(i=0;i<8;i++) + { + printk("*%08lx == %08lx, ", + (unsigned long)p, (unsigned long)*p++); + printk("*%08lx == %08lx\n", + (unsigned long)p, (unsigned long)*p++); + } +} diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/rtc-no.c linux/arch/mips/lib/rtc-no.c --- v2.3.47/linux/arch/mips/lib/rtc-no.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/rtc-no.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: rtc-no.c,v 1.2 1998/06/25 20:19:15 ralf Exp $ +/* $Id: rtc-no.c,v 1.1 1998/06/30 00:21:55 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 diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/rtc-std.c linux/arch/mips/lib/rtc-std.c --- v2.3.47/linux/arch/mips/lib/rtc-std.c Tue Oct 20 13:52:54 1998 +++ linux/arch/mips/lib/rtc-std.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: rtc-std.c,v 1.2 1998/06/25 20:19:16 ralf Exp $ +/* $Id: rtc-std.c,v 1.1 1998/06/30 00:21:55 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 diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/strlen_user.S linux/arch/mips/lib/strlen_user.S --- v2.3.47/linux/arch/mips/lib/strlen_user.S Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/lib/strlen_user.S Thu Feb 24 22:52:30 2000 @@ -1,13 +1,11 @@ -/* - * arch/mips/lib/strlen_user.S +/* $Id: strlen_user.S,v 1.4 1999/12/04 03:59:00 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1996, 1998 by Ralf Baechle - * - * $Id: strlen_user.S,v 1.2 1998/05/04 09:12:54 ralf Exp $ + * Copyright (c) 1996, 1998, 1999 by Ralf Baechle + * Copyright (c) 1999 Silicon Graphics, Inc. */ #include #include @@ -25,24 +23,23 @@ * * Return 0 for error */ -LEAF(__strlen_user_nocheck_asm) - lw v0, THREAD_CURDS($28) # pointer ok? - subu v0, zero, v0 +LEAF(__strlen_user_asm) + lw v0, THREAD_CURDS($28) # pointer ok? and v0, a0 - nor v0, zero, v0 - beqz v0, fault -EXPORT(__strlen_user_asm) - move v0, a0 + bltz v0, fault + +EXPORT(__strlen_user_nocheck_asm) + move v0, a0 1: EX(lb, t0, (v0), fault) - LONG_ADDIU v0, 1 - bnez t0, 1b - LONG_SUBU v0, a0 - jr ra + addiu v0, 1 + bnez t0, 1b + subu v0, a0 + jr ra END(__strlen_user_nocheck_asm) - .section __ex_table,"a" - PTR 1b, fault + .section __ex_table,"a" + PTR 1b, fault .previous -fault: move v0, zero - jr ra +fault: move v0, zero + jr ra diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/strncpy_user.S linux/arch/mips/lib/strncpy_user.S --- v2.3.47/linux/arch/mips/lib/strncpy_user.S Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/lib/strncpy_user.S Thu Feb 24 22:52:30 2000 @@ -1,13 +1,10 @@ -/* - * arch/mips/lib/strncpy_user.S +/* $Id: strncpy_user.S,v 1.4 1999/12/04 03:59:00 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (c) 1996 by Ralf Baechle - * - * $Id: strncpy_user.S,v 1.2 1998/05/04 09:12:54 ralf Exp $ + * Copyright (c) 1996, 1999 by Ralf Baechle */ #include #include @@ -32,32 +29,31 @@ */ LEAF(__strncpy_from_user_asm) - lw v0, THREAD_CURDS($28) # pointer ok? - subu v0, zero, v0 + lw v0, THREAD_CURDS($28) # pointer ok? and v0, a1 - nor v0, zero, v0 - beqz v0, fault + bltz v0, fault + EXPORT(__strncpy_from_user_nocheck_asm) - move v0,zero - move v1,a1 - .set noreorder + move v0, zero + move v1, a1 + .set noreorder 1: EX(lbu, t0, (v1), fault) - LONG_ADDIU v1,1 - beqz t0,2f - sb t0,(a0) - LONG_ADDIU v0,1 - bne v0,a2,1b - LONG_ADDIU a0,1 - .set reorder -2: LONG_ADDU t0,a1,v0 - xor t0,a1 - bltz t0,fault - jr ra # return n + addiu v1, v1, 1 + beqz t0, 2f + sb t0, (a0) + addiu v0, 1 + bne v0, a2, 1b + addiu a0, 1 + .set reorder +2: addu t0, a1, v0 + xor t0, a1 + bltz t0, fault + jr ra # return n END(__strncpy_from_user_asm) -fault: li v0,-EFAULT - jr ra +fault: li v0, -EFAULT + jr ra - .section __ex_table,"a" - PTR 1b,fault + .section __ex_table,"a" + PTR 1b, fault .previous diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/strnlen_user.S linux/arch/mips/lib/strnlen_user.S --- v2.3.47/linux/arch/mips/lib/strnlen_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/lib/strnlen_user.S Thu Feb 24 22:52:30 2000 @@ -0,0 +1,54 @@ +/* $Id: strnlen_user.S,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1996, 1998, 1999 by Ralf Baechle + * Copyright (c) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include + +#define EX(insn,reg,addr,handler) \ +9: insn reg, addr; \ + .section __ex_table,"a"; \ + PTR 9b, handler; \ + .previous + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 for error, len of string but at max a1 otherwise + * + * Note: for performance reasons we deliberately accept that a user may + * make strlen_user and strnlen_user access the first few KSEG0 + * bytes. There's nothing secret there ... + */ +LEAF(__strnlen_user_asm) + lw v0, THREAD_CURDS($28) # pointer ok? + and v0, a0 + bltz v0, fault + +EXPORT(__strnlen_user_nocheck_asm) + .type __strnlen_user_nocheck_asm,@function + move v0, a0 + addu a1, a0 # stop pointer + .set noreorder +1: beq v0, a1, 1f # limit reached? + addiu v0, 1 + .set reorder + EX(lb, t0, -1(v0), fault) + bnez t0, 1b +1: subu v0, a0 + jr ra + END(__strnlen_user_asm) + + .section __ex_table,"a" + PTR 1b, fault + .previous + +fault: move v0, zero + jr ra diff -u --recursive --new-file v2.3.47/linux/arch/mips/lib/watch.S linux/arch/mips/lib/watch.S --- v2.3.47/linux/arch/mips/lib/watch.S Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/lib/watch.S Thu Feb 24 22:52:30 2000 @@ -1,12 +1,13 @@ -/* - * Kernel debug stuff to use the Watch registers. - * Useful to find stack overflows, dangling pointers etc. +/* $Id: watch.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. * - * Copyright (C) 1995, 1996 by Ralf Baechle + * Kernel debug stuff to use the Watch registers. + * Useful to find stack overflows, dangling pointers etc. + * + * Copyright (C) 1995, 1996, 1999 by Ralf Baechle */ #include #include @@ -48,7 +49,6 @@ */ LEAF(__watch_reenable) lw t0,watch_savelo - jr ra mtc0 t0,CP0_WATCHLO END(__watch_reenable) @@ -59,67 +59,3 @@ .data watch_savelo: .word 0 .text - -/* - * The stuff below are just some kernel debugging gadgets. It is only here - * because it had to be somewhere and will go away. - */ - -/* - * Parameter: none - * Results : none - */ - LEAF(get_sp) - jr ra - move v0,sp - END(get_sp) - -/* - * Parameter: none - * Results : none - */ - LEAF(get_ra) - jr ra - move v0,ra - END(get_ra) - -/* - * Parameter: none - * Results : none - */ - LEAF(get_status) - jr ra - mfc0 v0,CP0_STATUS - END(get_status) - -/* - * Parameter: none - * Results : none - */ - NESTED(print_sp, ((5*SZREG)+ALSZ)&ALMASK, sp) - .mask 0x80000000,4*SZREG - PTR_SUBU sp,((5*SZREG)+ALSZ)&ALMASK - REG_S ra,4*SZREG(sp) - move a1,sp - PRINT("$sp == %08lx\n") - REG_L ra,4*SZREG(sp) - - jr ra - PTR_ADDU sp,((5*SZREG)+ALSZ)&ALMASK - END(print_sp) - -/* - * Parameter: none - * Results : none - */ - NESTED(print_st, ((5*SZREG)+ALSZ)&ALMASK, sp) - .mask 0x80000000,4*SZREG - PTR_SUBU sp,((5*SZREG)+ALSZ)&ALMASK - REG_S ra,4*SZREG(sp) - mfc0 a1,CP0_STATUS - PRINT("cp0_status == %08lx\n") - REG_L ra,4*SZREG(sp) - - jr ra - PTR_ADDU sp,((5*SZREG)+ALSZ)&ALMASK - END(print_st) diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/Makefile linux/arch/mips/mm/Makefile --- v2.3.47/linux/arch/mips/mm/Makefile Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/mm/Makefile Thu Feb 24 22:52:30 2000 @@ -8,10 +8,29 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := extable.o init.o fault.o r4xx0.o r2300.o r6000.o tfp.o \ - andes.o loadmmu.o +O_OBJS := extable.o init.o fault.o loadmmu.o -ifdef CONFIG_SGI +ifdef CONFIG_CPU_R3000 +O_OBJS += r2300.o +endif + +ifdef CONFIG_CPU_R4300 +O_OBJS += r4xx0.o +endif + +ifdef CONFIG_CPU_R4X00 +O_OBJS += r4xx0.o +endif + +ifdef CONFIG_CPU_R5000 +O_OBJS += r4xx0.o +endif + +ifdef CONFIG_CPU_NEVADA +O_OBJS += r4xx0.o +endif + +ifdef CONFIG_SGI_IP22 O_OBJS += umap.o endif diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/andes.c linux/arch/mips/mm/andes.c --- v2.3.47/linux/arch/mips/mm/andes.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/mm/andes.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: andes.c,v 1.6 1999/01/04 16:03:52 ralf Exp $ +/* $Id: andes.c,v 1.11 2000/02/24 00:12:40 ralf Exp $ * * andes.c: MMU and cache operations for the R10000 (ANDES). * @@ -14,7 +14,82 @@ #include #include -extern unsigned long mips_tlb_entries; +/* 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) @@ -40,7 +115,7 @@ /* XXX */ } -static void andes_flush_page_to_ram(unsigned long page) +static void andes_flush_page_to_ram(struct page * page) { /* XXX */ } @@ -51,67 +126,52 @@ } /* TLB operations. XXX Write these dave... */ -static inline void andes_flush_tlb_all(void) +void flush_tlb_all(void) { /* XXX */ } -static void andes_flush_tlb_mm(struct mm_struct *mm) +void flush_tlb_mm(struct mm_struct *mm) { /* XXX */ } -static void andes_flush_tlb_range(struct mm_struct *mm, unsigned long start, +void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { /* XXX */ } -static void andes_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { /* XXX */ } -static void andes_load_pgd(unsigned long pg_dir) +void load_pgd(unsigned long pg_dir) { } -static void andes_pgd_init(unsigned long page) +void pgd_init(unsigned long page) { } -static void andes_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, +void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask) { /* XXX */ } -static int andes_user_mode(struct pt_regs *regs) -{ - return (regs->cp0_status & ST0_KSU) == KSU_USER; -} - void __init ld_mmu_andes(void) { - 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_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; - andes_asid_setup(); - - add_wired_entry = andes_add_wired_entry; - - user_mode = andes_user_mode; + _clear_page = andes_clear_page; + _copy_page = andes_copy_page; - load_pgd = andes_load_pgd; - pgd_init = andes_pgd_init; + _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_cache_all(); flush_tlb_all(); diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/extable.c linux/arch/mips/mm/extable.c --- v2.3.47/linux/arch/mips/mm/extable.c Thu Jun 26 12:33:38 1997 +++ linux/arch/mips/mm/extable.c Thu Feb 24 22:52:30 2000 @@ -8,7 +8,7 @@ extern const struct exception_table_entry __start___ex_table[]; extern const struct exception_table_entry __stop___ex_table[]; -static inline unsigned +static inline unsigned long search_one_table(const struct exception_table_entry *first, const struct exception_table_entry *last, unsigned long value) diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c --- v2.3.47/linux/arch/mips/mm/fault.c Fri Jul 23 12:20:23 1999 +++ linux/arch/mips/mm/fault.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.9 1999/01/04 16:03:53 ralf Exp $ +/* $Id: fault.c,v 1.16 2000/02/18 00:24:30 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include @@ -29,9 +29,7 @@ #define development_version (LINUX_VERSION_CODE & 0x100) -extern void die(char *, struct pt_regs *, unsigned long write); - -unsigned long asid_cache; +unsigned long asid_cache = ASID_FIRST_VERSION; /* * Macro for exception fixup code to access integer registers. @@ -49,6 +47,7 @@ struct vm_area_struct * vma; struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; + int si_code = SEGV_MAPERR; unsigned long fixup; /* @@ -76,6 +75,8 @@ * we can handle it.. */ good_area: + si_code = SEGV_ACCERR; + if (write) { if (!(vma->vm_flags & VM_WRITE)) goto bad_area; @@ -96,6 +97,7 @@ if (!fault) goto do_sigbus; } + up(&mm->mmap_sem); return; @@ -107,8 +109,9 @@ up(&mm->mmap_sem); if (user_mode(regs)) { - tsk->tss.cp0_badvaddr = address; - tsk->tss.error_code = write; + struct siginfo si; + tsk->thread.cp0_badvaddr = address; + tsk->thread.error_code = write; #if 0 printk("do_page_fault() #2: sending SIGSEGV to %s for illegal %s\n" "%08lx (epc == %08lx, ra == %08lx)\n", @@ -118,7 +121,10 @@ (unsigned long) regs->cp0_epc, (unsigned long) regs->regs[31]); #endif - force_sig(SIGSEGV, tsk); + si.si_signo = SIGSEGV; + si.si_code = si_code; + si.si_addr = (void *) address; + force_sig_info(SIGSEGV, &si, tsk); return; } @@ -128,7 +134,7 @@ if (fixup) { long new_epc; - tsk->tss.cp0_baduaddr = address; + tsk->thread.cp0_baduaddr = address; new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc); if (development_version) printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n", @@ -144,7 +150,7 @@ printk(KERN_ALERT "Unable to handle kernel paging request at virtual " "address %08lx, epc == %08lx, ra == %08lx\n", address, regs->cp0_epc, regs->regs[31]); - die("Oops", regs, write); + die("Oops", regs); do_exit(SIGKILL); /* @@ -164,8 +170,8 @@ /* * Send a sigbus, regardless of whether we were in kernel * or user mode. - * XXX Store details about fault for siginfo handling into tss. */ + tsk->thread.cp0_badvaddr = address; force_sig(SIGBUS, tsk); /* Kernel mode? Handle exceptions or die */ diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c --- v2.3.47/linux/arch/mips/mm/init.c Thu Feb 10 17:11:04 2000 +++ linux/arch/mips/mm/init.c Thu Feb 24 22:52:30 2000 @@ -1,10 +1,11 @@ -/* $Id: init.c,v 1.13 1999/05/01 22:40:40 ralf Exp $ +/* $Id: init.c,v 1.27 2000/02/23 01:33:56 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1994 - 1998 by Ralf Baechle + * Copyright (C) 1994 - 2000 by Ralf Baechle + * Copyright (C) 2000 Silicon Graphics, Inc. */ #include #include @@ -18,6 +19,8 @@ #include #include #include +#include +#include #include #include #ifdef CONFIG_BLK_DEV_INITRD @@ -30,21 +33,28 @@ #include #include #include -#ifdef CONFIG_SGI +#include +#ifdef CONFIG_SGI_IP22 #include #endif #include +static unsigned long totalram_pages = 0; + +extern void prom_fixup_mem_map(unsigned long start, unsigned long end); +extern void prom_free_prom_memory(void); + + void __bad_pte_kernel(pmd_t *pmd) { printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); - pmd_val(*pmd) = BAD_PAGETABLE; + pmd_set(pmd, BAD_PAGETABLE); } void __bad_pte(pmd_t *pmd) { printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_val(*pmd) = BAD_PAGETABLE; + pmd_set(pmd, BAD_PAGETABLE); } pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) @@ -54,11 +64,11 @@ page = (pte_t *) __get_free_page(GFP_USER); if (pmd_none(*pmd)) { if (page) { - clear_page((unsigned long)page); + clear_page(page); pmd_val(*pmd) = (unsigned long)page; return page + offset; } - pmd_val(*pmd) = BAD_PAGETABLE; + pmd_set(pmd, BAD_PAGETABLE); return NULL; } free_page((unsigned long)page); @@ -76,11 +86,11 @@ page = (pte_t *) __get_free_page(GFP_KERNEL); if (pmd_none(*pmd)) { if (page) { - clear_page((unsigned long)page); + clear_page(page); pmd_val(*pmd) = (unsigned long)page; return page + offset; } - pmd_val(*pmd) = BAD_PAGETABLE; + pmd_set(pmd, BAD_PAGETABLE); return NULL; } free_page((unsigned long)page); @@ -128,9 +138,9 @@ panic("Oh boy, that early out of memory?"); pg = MAP_NR(empty_zero_page); - while(pg < MAP_NR(empty_zero_page) + (1 << order)) { + while (pg < MAP_NR(empty_zero_page) + (1 << order)) { set_bit(PG_reserved, &mem_map[pg].flags); - atomic_set(&mem_map[pg].count, 0); + set_page_count(mem_map + pg, 0); pg++; } @@ -138,7 +148,7 @@ zero_page_mask = (size - 1) & PAGE_MASK; memset((void *)empty_zero_page, 0, size); - return size; + return 1UL << order; } int do_check_pgt_cache(int low, int high) @@ -174,43 +184,9 @@ pte_t * __bad_pagetable(void) { extern char empty_bad_page_table[PAGE_SIZE]; - unsigned long page; - unsigned long dummy1, dummy2; -#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) - unsigned long dummy3; -#endif + unsigned long page, dummy1, dummy2; page = (unsigned long) empty_bad_page_table; - /* - * As long as we only save the low 32 bit of the 64 bit wide - * R4000 registers on interrupt we cannot use 64 bit memory accesses - * to the main memory. - */ -#if (_MIPS_ISA == _MIPS_ISA_MIPS3) || (_MIPS_ISA == _MIPS_ISA_MIPS4) - /* - * Use 64bit code even for Linux/MIPS 32bit on R4000 - */ - __asm__ __volatile__( - ".set\tnoreorder\n" - ".set\tnoat\n\t" - ".set\tmips3\n\t" - "dsll32\t$1,%2,0\n\t" - "dsrl32\t%2,$1,0\n\t" - "or\t%2,$1\n" - "1:\tsd\t%2,(%0)\n\t" - "subu\t%1,1\n\t" - "bnez\t%1,1b\n\t" - "addiu\t%0,8\n\t" - ".set\tmips0\n\t" - ".set\tat\n" - ".set\treorder" - :"=r" (dummy1), - "=r" (dummy2), - "=r" (dummy3) - :"0" (page), - "1" (PAGE_SIZE/8), - "2" (pte_val(BAD_PAGE))); -#else /* (_MIPS_ISA == _MIPS_ISA_MIPS1) || (_MIPS_ISA == _MIPS_ISA_MIPS2) */ __asm__ __volatile__( ".set\tnoreorder\n" "1:\tsw\t%2,(%0)\n\t" @@ -218,12 +194,9 @@ "bnez\t%1,1b\n\t" "addiu\t%0,4\n\t" ".set\treorder" - :"=r" (dummy1), - "=r" (dummy2) - :"r" (pte_val(BAD_PAGE)), - "0" (page), - "1" (PAGE_SIZE/4)); -#endif + :"=r" (dummy1), "=r" (dummy2) + :"r" (pte_val(BAD_PAGE)), "0" (page), "1" (PAGE_SIZE/4) + :"$1"); return (pte_t *)page; } @@ -231,10 +204,10 @@ pte_t __bad_page(void) { extern char empty_bad_page[PAGE_SIZE]; - unsigned long page = (unsigned long)empty_bad_page; + unsigned long page = (unsigned long) empty_bad_page; - clear_page(page); - return pte_mkdirty(mk_pte(page, PAGE_SHARED)); + clear_page((void *)page); + return pte_mkdirty(mk_pte_phys(__pa(page), PAGE_SHARED)); } void show_mem(void) @@ -252,10 +225,10 @@ reserved++; else if (PageSwapCache(mem_map+i)) cached++; - else if (!atomic_read(&mem_map[i].count)) + else if (!page_count(mem_map + i)) free++; else - shared += atomic_read(&mem_map[i].count) - 1; + shared += page_count(mem_map + i) - 1; } printk("%d pages of RAM\n", total); printk("%d reserved pages\n", reserved); @@ -266,79 +239,83 @@ show_buffers(); } -extern unsigned long free_area_init(unsigned long, unsigned long); +/* References to section boundaries */ -unsigned long __init paging_init(unsigned long start_mem, unsigned long end_mem) +extern char _ftext, _etext, _fdata, _edata; +extern char __init_begin, __init_end; + +void __init paging_init(void) { + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long max_dma, low; + /* Initialize the entire pgd. */ pgd_init((unsigned long)swapper_pg_dir); pgd_init((unsigned long)swapper_pg_dir + PAGE_SIZE / 2); - return free_area_init(start_mem, end_mem); + + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + low = max_low_pfn; + + if (low < max_dma) + zones_size[ZONE_DMA] = low; + else { + zones_size[ZONE_DMA] = max_dma; + zones_size[ZONE_NORMAL] = low - max_dma; + } + + free_area_init(zones_size); } -void __init mem_init(unsigned long start_mem, unsigned long end_mem) +extern int page_is_ram(unsigned long pagenr); + +void __init mem_init(void) { - int codepages = 0; - int datapages = 0; - unsigned long tmp; - extern int _etext, _ftext; + unsigned long codesize, reservedpages, datasize, initsize; + unsigned long tmp, ram; -#ifdef CONFIG_MIPS_JAZZ - if (mips_machgroup == MACH_GROUP_JAZZ) - start_mem = vdma_init(start_mem, end_mem); -#endif + max_mapnr = num_physpages = max_low_pfn; + high_memory = (void *) __va(max_mapnr << PAGE_SHIFT); - end_mem &= PAGE_MASK; - max_mapnr = MAP_NR(end_mem); - high_memory = (void *)end_mem; - num_physpages = 0; - - /* mark usable pages in the mem_map[] */ - start_mem = PAGE_ALIGN(start_mem); - - for(tmp = MAP_NR(start_mem);tmp < max_mapnr;tmp++) - clear_bit(PG_reserved, &mem_map[tmp].flags); - - prom_fixup_mem_map(start_mem, (unsigned long)high_memory); - - for (tmp = PAGE_OFFSET; tmp < end_mem; tmp += PAGE_SIZE) { - /* - * This is only for PC-style DMA. The onboard DMA - * of Jazz and Tyne machines is completely different and - * not handled via a flag in mem_map_t. - */ - if (tmp >= MAX_DMA_ADDRESS) - clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags); - if (PageReserved(mem_map+MAP_NR(tmp))) { - if ((tmp < (unsigned long) &_etext) && - (tmp >= (unsigned long) &_ftext)) - codepages++; - else if ((tmp < start_mem) && - (tmp > (unsigned long) &_etext)) - datapages++; - continue; + totalram_pages += free_all_bootmem(); + totalram_pages -= setup_zero_pages(); /* Setup zeroed pages. */ + + reservedpages = ram = 0; + for (tmp = 0; tmp < max_low_pfn; tmp++) + if (page_is_ram(tmp)) { + ram++; + if (PageReserved(mem_map+tmp)) + reservedpages++; } - num_physpages++; - atomic_set(&mem_map[MAP_NR(tmp)].count, 1); -#ifdef CONFIG_BLK_DEV_INITRD - if (!initrd_start || (tmp < initrd_start || tmp >= - initrd_end)) -#endif - free_page(tmp); - } - tmp = nr_free_pages << PAGE_SHIFT; - /* Setup zeroed pages. */ - tmp -= setup_zero_pages(); + 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", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + ram << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10); +} - printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n", - tmp >> 10, - max_mapnr << (PAGE_SHIFT-10), - codepages << (PAGE_SHIFT-10), - datapages << (PAGE_SHIFT-10)); +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + 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 - start) >> 10); } +#endif extern char __init_begin, __init_end; +extern void prom_free_prom_memory(void); void free_initmem(void) { @@ -346,11 +323,13 @@ prom_free_prom_memory (); - addr = (unsigned long)(&__init_begin); - for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { - mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved); - atomic_set(&mem_map[MAP_NR(addr)].count, 1); + addr = (unsigned long) &__init_begin; + while (addr < (unsigned long) &__init_end) { + ClearPageReserved(mem_map + MAP_NR(addr)); + set_page_count(mem_map + MAP_NR(addr), 1); free_page(addr); + totalram_pages++; + addr += PAGE_SIZE; } printk("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); @@ -358,54 +337,13 @@ void si_meminfo(struct sysinfo *val) { - int i; - - i = MAP_NR(high_memory); - val->totalram = 0; + val->totalram = totalram_pages; val->sharedram = 0; - val->freeram = nr_free_pages << PAGE_SHIFT; - val->bufferram = atomic_read(&buffermem); - while (i-- > 0) { - if (PageReserved(mem_map+i)) - continue; - val->totalram++; - if (!atomic_read(&mem_map[i].count)) - continue; - val->sharedram += atomic_read(&mem_map[i].count) - 1; - } - val->totalram <<= PAGE_SHIFT; - val->sharedram <<= PAGE_SHIFT; - return; -} - -/* Fixup an immediate instruction */ -static void __init __i_insn_fixup(unsigned int **start, unsigned int **stop, - unsigned int i_const) -{ - unsigned int **p, *ip; - - for (p = start;p < stop; p++) { - ip = *p; - *ip = (*ip & 0xffff0000) | i_const; - } -} - -#define i_insn_fixup(section, const) \ -do { \ - extern unsigned int *__start_ ## section; \ - extern unsigned int *__stop_ ## section; \ - __i_insn_fixup(&__start_ ## section, &__stop_ ## section, const); \ -} while(0) + val->freeram = nr_free_pages(); + val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = 0; + val->freehigh = nr_free_highpages(); + val->mem_unit = PAGE_SIZE; -/* Caller is assumed to flush the caches before the first context switch. */ -void __init __asid_setup(unsigned int inc, unsigned int mask, - unsigned int version_mask, - unsigned int first_version) -{ - i_insn_fixup(__asid_inc, inc); - i_insn_fixup(__asid_mask, mask); - i_insn_fixup(__asid_version_mask, version_mask); - i_insn_fixup(__asid_first_version, first_version); - - asid_cache = first_version; + return; } diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/loadmmu.c linux/arch/mips/mm/loadmmu.c --- v2.3.47/linux/arch/mips/mm/loadmmu.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/mm/loadmmu.c Thu Feb 24 22:52:30 2000 @@ -3,7 +3,7 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: loadmmu.c,v 1.10 1999/06/17 13:25:51 ralf Exp $ + * $Id: loadmmu.c,v 1.15 2000/02/24 00:12:40 ralf Exp $ */ #include #include @@ -17,61 +17,54 @@ #include /* memory functions */ -void (*clear_page)(unsigned long page); -void (*copy_page)(unsigned long to, unsigned long from); +void (*_clear_page)(void * page); +void (*_copy_page)(void * to, void * from); /* Cache operations. */ -void (*flush_cache_all)(void); -void (*flush_cache_mm)(struct mm_struct *mm); -void (*flush_cache_range)(struct mm_struct *mm, unsigned long start, +void (*_flush_cache_all)(void); +void (*_flush_cache_mm)(struct mm_struct *mm); +void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start, unsigned long end); -void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page); -void (*flush_cache_sigtramp)(unsigned long addr); -void (*flush_page_to_ram)(unsigned long page); +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); /* 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); - -/* 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 (*load_pgd)(unsigned long pg_dir); -void (*pgd_init)(unsigned long page); -void (*update_mmu_cache)(struct vm_area_struct * vma, - unsigned long address, pte_t pte); - -void (*show_regs)(struct pt_regs *); - -void (*add_wired_entry)(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask); - -int (*user_mode)(struct pt_regs *); - -asmlinkage void *(*resume)(void *last, void *next); +void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size); +void (*_dma_cache_wback)(unsigned long start, unsigned long size); +void (*_dma_cache_inv)(unsigned long start, unsigned long size); +#ifdef CONFIG_CPU_R3000 extern void ld_mmu_r2300(void); +#endif +#if defined(CONFIG_CPU_R4X00) || defined(CONFIG_CPU_R4300) || \ + defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA) extern void ld_mmu_r4xx0(void); +#endif +#ifdef CONFIG_CPU_R6000 extern void ld_mmu_r6000(void); +#endif +#ifdef CONFIG_CPU_R8000 extern void ld_mmu_tfp(void); +#endif +#ifdef CONFIG_CPU_R10000 extern void ld_mmu_andes(void); +#endif void __init loadmmu(void) { switch(mips_cputype) { +#ifdef CONFIG_CPU_R3000 case CPU_R2000: case CPU_R3000: case CPU_R3000A: printk("Loading R[23]00 MMU routines.\n"); ld_mmu_r2300(); break; +#endif +#if defined(CONFIG_CPU_R4X00) || defined(CONFIG_CPU_R4300) || \ + defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA) case CPU_R4000PC: case CPU_R4000SC: case CPU_R4000MC: @@ -90,22 +83,14 @@ printk("Loading R4000 MMU routines.\n"); ld_mmu_r4xx0(); break; +#endif - case CPU_R6000: - case CPU_R6000A: - printk("Loading R6000 MMU routines.\n"); - ld_mmu_r6000(); - break; - - case CPU_R8000: - printk("Loading TFP MMU routines.\n"); - ld_mmu_tfp(); - break; - +#ifdef CONFIG_CPU_R10000 case CPU_R10000: printk("Loading R10000 MMU routines.\n"); ld_mmu_andes(); break; +#endif default: /* XXX We need an generic routine in the MIPS port diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/r2300.c linux/arch/mips/mm/r2300.c --- v2.3.47/linux/arch/mips/mm/r2300.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/mm/r2300.c Thu Feb 24 22:52:30 2000 @@ -4,10 +4,10 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * * with a lot of changes to make this thing work for R3000s - * Copyright (C) 1998 Harald Koerfgen + * Copyright (C) 1998, 2000 Harald Koerfgen * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov * - * $Id: r2300.c,v 1.8 1999/04/11 17:13:56 harald Exp $ + * $Id: r2300.c,v 1.15 2000/02/24 00:12:40 ralf Exp $ */ #include #include @@ -19,13 +19,9 @@ #include #include #include -#include +#include #include -/* - * Temporarily disabled - * #include - */ /* * According to the paper written by D. Miller about Linux cache & TLB @@ -33,25 +29,18 @@ * driver layer. Thus, normally, we don't need flush dcache for R3000. * Define this if driver does not handle cache consistency during DMA ops. */ -#undef DO_DCACHE_FLUSH -/* - * Unified cache space description structure - */ -static struct cache_space { - unsigned long ca_flags; /* Cache space access flags */ - int size; /* Cache space size */ -} icache, dcache; +/* Primary cache parameters. */ +static int icache_size, dcache_size; /* Size in bytes */ +/* the linesizes are usually fixed on R3000s */ #undef DEBUG_TLB #undef DEBUG_CACHE -extern unsigned long mips_tlb_entries; - #define NTLB_ENTRIES 64 /* Fixed on all R23000 variants... */ /* page functions */ -void r2300_clear_page(unsigned long page) +void r3k_clear_page(void * page) { __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -75,7 +64,7 @@ :"$1","memory"); } -static void r2300_copy_page(unsigned long to, unsigned long from) +static void r3k_copy_page(void * to, void * from) { unsigned long dummy1, dummy2; unsigned long reg1, reg2, reg3, reg4; @@ -163,278 +152,248 @@ static void __init probe_dcache(void) { - dcache.size = size_cache(dcache.ca_flags = ST0_DE); - printk("Data cache %dkb\n", dcache.size >> 10); + dcache_size = size_cache(ST0_DE); + printk("Primary data cache %dkb, linesize 4 bytes\n", + dcache_size >> 10); } static void __init probe_icache(void) { - icache.size = size_cache(icache.ca_flags = ST0_DE|ST0_CE); - printk("Instruction cache %dkb\n", icache.size >> 10); + icache_size = size_cache(ST0_DE|ST0_CE); + printk("Primary instruction cache %dkb, linesize 8 bytes\n", + icache_size >> 10); } -static inline unsigned long get_phys_page (unsigned long page, - struct mm_struct *mm) +static void r3k_flush_icache_range(unsigned long start, unsigned long size) { - page &= PAGE_MASK; - if (page >= KSEG0 && page < KSEG1) { - /* - * We already have physical address - */ - return page; - } else { - if (!mm) { - printk ("get_phys_page: vaddr without mm\n"); - return 0; - } else { - /* - * Find a physical page using mm_struct - */ - pgd_t *page_dir; - pmd_t *page_middle; - pte_t *page_table, pte; - - unsigned long address = page; - - page_dir = pgd_offset(mm, address); - if (pgd_none(*page_dir)) - return 0; - page_middle = pmd_offset(page_dir, address); - if (pmd_none(*page_middle)) - return 0; - page_table = pte_offset(page_middle, address); - pte = *page_table; - if (!pte_present(pte)) - return 0; - return pte_page(pte); - } + unsigned long i, flags; + volatile unsigned char *p = (char *)start; + + if (size > icache_size) + size = icache_size; + + save_and_cli(flags); + + /* isolate cache space */ + write_32bit_cp0_register(CP0_STATUS, (ST0_DE|ST0_CE|flags)&~ST0_IEC); + + for (i = 0; i < size; i += 0x100) { + asm ( "sb\t$0,0x000(%0)\n\t" + "sb\t$0,0x008(%0)\n\t" + "sb\t$0,0x010(%0)\n\t" + "sb\t$0,0x018(%0)\n\t" + "sb\t$0,0x020(%0)\n\t" + "sb\t$0,0x028(%0)\n\t" + "sb\t$0,0x030(%0)\n\t" + "sb\t$0,0x038(%0)\n\t" + "sb\t$0,0x040(%0)\n\t" + "sb\t$0,0x048(%0)\n\t" + "sb\t$0,0x050(%0)\n\t" + "sb\t$0,0x058(%0)\n\t" + "sb\t$0,0x060(%0)\n\t" + "sb\t$0,0x068(%0)\n\t" + "sb\t$0,0x070(%0)\n\t" + "sb\t$0,0x078(%0)\n\t" + "sb\t$0,0x080(%0)\n\t" + "sb\t$0,0x088(%0)\n\t" + "sb\t$0,0x090(%0)\n\t" + "sb\t$0,0x098(%0)\n\t" + "sb\t$0,0x0a0(%0)\n\t" + "sb\t$0,0x0a8(%0)\n\t" + "sb\t$0,0x0b0(%0)\n\t" + "sb\t$0,0x0b8(%0)\n\t" + "sb\t$0,0x0c0(%0)\n\t" + "sb\t$0,0x0c8(%0)\n\t" + "sb\t$0,0x0d0(%0)\n\t" + "sb\t$0,0x0d8(%0)\n\t" + "sb\t$0,0x0e0(%0)\n\t" + "sb\t$0,0x0e8(%0)\n\t" + "sb\t$0,0x0f0(%0)\n\t" + "sb\t$0,0x0f8(%0)\n\t" + : : "r" (p) ); + p += 0x100; } + + restore_flags(flags); } -static inline void flush_cache_space_page(struct cache_space *space, - unsigned long page) +static void r3k_flush_dcache_range(unsigned long start, unsigned long size) { - register unsigned long i, flags, size = space->size; - register volatile unsigned char *p = (volatile unsigned char*) page; + unsigned long i, flags; + volatile unsigned char *p = (char *)start; -#ifndef DO_DCACHE_FLUSH - if (space == &dcache) - return; -#endif - if (size > PAGE_SIZE) - size = PAGE_SIZE; + if (size > icache_size) + size = icache_size; save_and_cli(flags); /* isolate cache space */ - write_32bit_cp0_register(CP0_STATUS, (space->ca_flags|flags)&~ST0_IEC); + write_32bit_cp0_register(CP0_STATUS, (ST0_DE|flags)&~ST0_IEC); - for (i = 0; i < size; i += 64) { - asm ( "sb\t$0,(%0)\n\t" - "sb\t$0,4(%0)\n\t" - "sb\t$0,8(%0)\n\t" - "sb\t$0,12(%0)\n\t" - "sb\t$0,16(%0)\n\t" - "sb\t$0,20(%0)\n\t" - "sb\t$0,24(%0)\n\t" - "sb\t$0,28(%0)\n\t" - "sb\t$0,32(%0)\n\t" - "sb\t$0,36(%0)\n\t" - "sb\t$0,40(%0)\n\t" - "sb\t$0,44(%0)\n\t" - "sb\t$0,48(%0)\n\t" - "sb\t$0,52(%0)\n\t" - "sb\t$0,56(%0)\n\t" - "sb\t$0,60(%0)\n\t" + 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 += 64; + p += 0x080; } restore_flags(flags); } -static inline void flush_cache_space_all(struct cache_space *space) +static inline unsigned long get_phys_page (unsigned long addr, + struct mm_struct *mm) { - unsigned long page = KSEG0; - int size = space->size; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long physpage; -#ifndef DO_DCACHE_FLUSH - if (space == &dcache) - return; -#endif - while(size > 0) { - flush_cache_space_page(space, page); - page += PAGE_SIZE; size -= PAGE_SIZE; - } + pgd = pgd_offset(mm, addr); + pmd = pmd_offset(pgd, addr); + pte = pte_offset(pmd, addr); + + if((physpage = pte_val(*pte)) & _PAGE_VALID) + return KSEG1ADDR(physpage & PAGE_MASK); + else + return 0; } -static inline void r2300_flush_cache_all(void) +static inline void r3k_flush_cache_all(void) { - flush_cache_space_all(&dcache); - flush_cache_space_all(&icache); + r3k_flush_icache_range(KSEG0, icache_size); } -static void r2300_flush_cache_mm(struct mm_struct *mm) +static void r3k_flush_cache_mm(struct mm_struct *mm) { - if(mm->context == 0) - return; + if(mm->context != 0) { + #ifdef DEBUG_CACHE printk("cmm[%d]", (int)mm->context); #endif - /* - * This function is called not offen, so it looks - * enough good to flush all caches than scan mm_struct, - * count pages to flush (and, very probably, flush more - * than cache space size :-) - */ - flush_cache_all(); + r3k_flush_cache_all(); + } } -static void r2300_flush_cache_range(struct mm_struct *mm, +static void r3k_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - /* - * In general, we need to flush both i- & d- caches here. - * Optimization: if cache space is less than given range, - * it is more quickly to flush all cache than all pages in range. - */ - - unsigned long page; - int icache_done = 0, dcache_done = 0; + struct vm_area_struct *vma; if(mm->context == 0) return; + + start &= PAGE_MASK; #ifdef DEBUG_CACHE - printk("crange[%d]", (int)mm->context); + printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - if (end - start >= icache.size) { - flush_cache_space_all(&icache); - icache_done = 1; - } - if (end - start >= dcache.size) { - flush_cache_space_all(&dcache); - dcache_done = 1; - } - if (icache_done && dcache_done) - return; + vma = find_vma(mm, start); + if(vma) { + if(mm->context != current->mm->context) { + flush_cache_all(); + } else { + unsigned long flags, physpage; - for (page = start; page < end; page += PAGE_SIZE) { - unsigned long phys_page = get_phys_page(page, mm); + save_and_cli(flags); + while(start < end) { + if((physpage = get_phys_page(start, mm))) + r3k_flush_icache_range(physpage, PAGE_SIZE); - if (phys_page) { - if (!icache_done) - flush_cache_space_page(&icache, phys_page); - if (!dcache_done) - flush_cache_space_page(&dcache, phys_page); + start += PAGE_SIZE; + } + restore_flags(flags); } } } -static void r2300_flush_cache_page(struct vm_area_struct *vma, +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 - /* - * User changes page, so we need to check: - * is icache page flush needed ? - * It looks we don't need to flush dcache, - * due it is write-transparent on R3000 - */ if (vma->vm_flags & VM_EXEC) { - unsigned long phys_page = get_phys_page(page, vma->vm_mm); - if (phys_page) - flush_cache_space_page(&icache, phys_page); + unsigned long physpage; + + if((physpage = get_phys_page(page, vma->vm_mm))) + r3k_flush_icache_range(physpage, PAGE_SIZE); + } } -static void r2300_flush_page_to_ram(unsigned long page) +static void r3k_flush_page_to_ram(struct page * page) { /* - * We need to flush both i- & d- caches :-( + * Nothing to be done */ - unsigned long phys_page = get_phys_page(page, NULL); -#ifdef DEBUG_CACHE - printk("cram[%08lx]", page); -#endif - if (phys_page) { - flush_cache_space_page(&icache, phys_page); - flush_cache_space_page(&dcache, phys_page); - } } -static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size) +static void r3k_flush_cache_sigtramp(unsigned long addr) { - register unsigned long i, flags; - register volatile unsigned char *p = (volatile unsigned char*) start; - -/* - * Temporarily disabled - wbflush(); - */ + unsigned long flags; +#ifdef DEBUG_CACHE + printk("csigtramp[%08lx]", addr); +#endif /* - * Invalidate dcache + * I am assuming an 8 Byte cacheline here. HK */ - if (size < 64) - size = 64; - - if (size > dcache.size) - size = dcache.size; + addr &= ~7; save_and_cli(flags); - /* isolate cache space */ - write_32bit_cp0_register(CP0_STATUS, (ST0_DE|flags)&~ST0_IEC); + write_32bit_cp0_register(CP0_STATUS, (ST0_DE|ST0_CE|flags)&~ST0_IEC); - for (i = 0; i < size; i += 64) { - asm ( "sb\t$0,(%0)\n\t" - "sb\t$0,4(%0)\n\t" - "sb\t$0,8(%0)\n\t" - "sb\t$0,12(%0)\n\t" - "sb\t$0,16(%0)\n\t" - "sb\t$0,20(%0)\n\t" - "sb\t$0,24(%0)\n\t" - "sb\t$0,28(%0)\n\t" - "sb\t$0,32(%0)\n\t" - "sb\t$0,36(%0)\n\t" - "sb\t$0,40(%0)\n\t" - "sb\t$0,44(%0)\n\t" - "sb\t$0,48(%0)\n\t" - "sb\t$0,52(%0)\n\t" - "sb\t$0,56(%0)\n\t" - "sb\t$0,60(%0)\n\t" - : : "r" (p) ); - p += 64; - } + asm ( "sb\t$0,0x000(%0)\n\t" + "sb\t$0,0x008(%0)\n\t" + : : "r" (addr) ); restore_flags(flags); } -static void r2300_flush_cache_sigtramp(unsigned long page) +static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size) { - /* - * We need only flush i-cache here - * - * This function receives virtual address (from signal.c), - * but this moment we have needed mm_struct in 'current' - */ - unsigned long phys_page = get_phys_page(page, current->mm); -#ifdef DEBUG_CACHE - printk("csigtramp[%08lx]", page); -#endif - if (phys_page) - flush_cache_space_page(&icache, phys_page); + wbflush(); + r3k_flush_dcache_range(start, size); } /* TLB operations. */ -static inline void r2300_flush_tlb_all(void) +void flush_tlb_all(void) { unsigned long flags; unsigned long old_ctx; @@ -456,7 +415,7 @@ restore_flags(flags); } -static void r2300_flush_tlb_mm(struct mm_struct *mm) +void flush_tlb_mm(struct mm_struct *mm) { if(mm->context != 0) { unsigned long flags; @@ -466,16 +425,16 @@ #endif save_and_cli(flags); get_new_mmu_context(mm, asid_cache); - if(mm == current->mm) + if (mm == current->active_mm) set_entryhi(mm->context & 0xfc0); restore_flags(flags); } } -static void r2300_flush_tlb_range(struct mm_struct *mm, unsigned long start, +void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - if(mm->context != 0) { + if (mm->context != 0) { unsigned long flags; int size; @@ -508,14 +467,14 @@ set_entryhi(oldpid); } else { get_new_mmu_context(mm, asid_cache); - if(mm == current->mm) + if (mm == current->active_mm) set_entryhi(mm->context & 0xfc0); } restore_flags(flags); } } -static void r2300_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { if(vma->vm_mm->context != 0) { unsigned long flags; @@ -543,15 +502,10 @@ } } -/* Load a new root pointer into the TLB. */ -static void r2300_load_pgd(unsigned long pg_dir) -{ -} - /* * Initialize new page directory with pointers to invalid ptes */ -static void r2300_pgd_init(unsigned long page) +void pgd_init(unsigned long page) { unsigned long dummy1, dummy2; @@ -580,7 +534,7 @@ "1" (PAGE_SIZE/(sizeof(pmd_t)*8))); } -static void r2300_update_mmu_cache(struct vm_area_struct * vma, +void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { unsigned long flags; @@ -636,7 +590,7 @@ restore_flags(flags); } -static void r2300_show_regs(struct pt_regs * regs) +void show_regs(struct pt_regs * regs) { /* * Saved main processor registers @@ -669,54 +623,33 @@ (unsigned int) regs->cp0_cause); } -static void r2300_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, +void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask) { -printk("r2300_add_wired_entry"); +printk("r3k_add_wired_entry"); /* * FIXME, to be done */ } -static int r2300_user_mode(struct pt_regs *regs) -{ - return !(regs->cp0_status & ST0_KUP); -} - void __init ld_mmu_r2300(void) { printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID)); - clear_page = r2300_clear_page; - copy_page = r2300_copy_page; + _clear_page = r3k_clear_page; + _copy_page = r3k_copy_page; probe_icache(); probe_dcache(); - flush_cache_all = r2300_flush_cache_all; - flush_cache_mm = r2300_flush_cache_mm; - flush_cache_range = r2300_flush_cache_range; - flush_cache_page = r2300_flush_cache_page; - flush_cache_sigtramp = r2300_flush_cache_sigtramp; - flush_page_to_ram = r2300_flush_page_to_ram; - - flush_tlb_all = r2300_flush_tlb_all; - flush_tlb_mm = r2300_flush_tlb_mm; - flush_tlb_range = r2300_flush_tlb_range; - flush_tlb_page = r2300_flush_tlb_page; - - dma_cache_wback_inv = r3k_dma_cache_wback_inv; - - load_pgd = r2300_load_pgd; - pgd_init = r2300_pgd_init; - update_mmu_cache = r2300_update_mmu_cache; - r3000_asid_setup(); - - show_regs = r2300_show_regs; - - add_wired_entry = r2300_add_wired_entry; + _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; - user_mode = r2300_user_mode; + _dma_cache_wback_inv = r3k_dma_cache_wback_inv; flush_tlb_all(); } diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c --- v2.3.47/linux/arch/mips/mm/r4xx0.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/mm/r4xx0.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: r4xx0.c,v 1.22 1999/06/17 13:25:51 ralf Exp $ +/* $Id: r4xx0.c,v 1.30 2000/02/24 01:12:37 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -22,13 +22,10 @@ #include #include -#include -#include #include #include #include #include -#include #include /* CP0 hazard avoidance. */ @@ -81,7 +78,7 @@ * versions of R4000 and R4400. */ -static void r4k_clear_page_d16(unsigned long page) +static void r4k_clear_page_d16(void * page) { __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -112,7 +109,7 @@ :"$1","memory"); } -static void r4k_clear_page_d32(unsigned long page) +static void r4k_clear_page_d32(void * page) { __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -169,7 +166,7 @@ * nop * cache Hit_Writeback_Invalidate_D */ -static void r4k_clear_page_r4600_v1(unsigned long page) +static void r4k_clear_page_r4600_v1(void * page) { __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -208,7 +205,7 @@ /* * And this one is for the R4600 V2.0 */ -static void r4k_clear_page_r4600_v2(unsigned long page) +static void r4k_clear_page_r4600_v2(void * page) { unsigned int flags; @@ -251,7 +248,7 @@ * this the kernel crashed shortly after mounting the root filesystem. CPU * bug? Weirdo cache instruction semantics? */ -static void r4k_clear_page_s16(unsigned long page) +static void r4k_clear_page_s16(void * page) { __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -282,7 +279,7 @@ :"$1","memory"); } -static void r4k_clear_page_s32(unsigned long page) +static void r4k_clear_page_s32(void * page) { __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -311,7 +308,7 @@ :"$1","memory"); } -static void r4k_clear_page_s64(unsigned long page) +static void r4k_clear_page_s64(void * page) { __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -339,7 +336,7 @@ :"$1","memory"); } -static void r4k_clear_page_s128(unsigned long page) +static void r4k_clear_page_s128(void * page) { __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -381,7 +378,7 @@ * virtual address where the copy will be accessed. */ -static void r4k_copy_page_d16(unsigned long to, unsigned long from) +static void r4k_copy_page_d16(void * to, void * from) { unsigned long dummy1, dummy2; unsigned long reg1, reg2, reg3, reg4; @@ -440,7 +437,7 @@ "i" (Create_Dirty_Excl_D)); } -static void r4k_copy_page_d32(unsigned long to, unsigned long from) +static void r4k_copy_page_d32(void * to, void * from) { unsigned long dummy1, dummy2; unsigned long reg1, reg2, reg3, reg4; @@ -500,7 +497,7 @@ /* * Again a special version for the R4600 V1.x */ -static void r4k_copy_page_r4600_v1(unsigned long to, unsigned long from) +static void r4k_copy_page_r4600_v1(void * to, void * from) { unsigned long dummy1, dummy2; unsigned long reg1, reg2, reg3, reg4; @@ -565,7 +562,7 @@ "i" (Create_Dirty_Excl_D)); } -static void r4k_copy_page_r4600_v2(unsigned long to, unsigned long from) +static void r4k_copy_page_r4600_v2(void * to, void * from) { unsigned long dummy1, dummy2; unsigned long reg1, reg2, reg3, reg4; @@ -636,7 +633,7 @@ /* * These are for R4000SC / R4400MC */ -static void r4k_copy_page_s16(unsigned long to, unsigned long from) +static void r4k_copy_page_s16(void * to, void * from) { unsigned long dummy1, dummy2; unsigned long reg1, reg2, reg3, reg4; @@ -695,7 +692,7 @@ "i" (Create_Dirty_Excl_SD)); } -static void r4k_copy_page_s32(unsigned long to, unsigned long from) +static void r4k_copy_page_s32(void * to, void * from) { unsigned long dummy1, dummy2; unsigned long reg1, reg2, reg3, reg4; @@ -752,7 +749,7 @@ "i" (Create_Dirty_Excl_SD)); } -static void r4k_copy_page_s64(unsigned long to, unsigned long from) +static void r4k_copy_page_s64(void * to, void * from) { unsigned long dummy1, dummy2; unsigned long reg1, reg2, reg3, reg4; @@ -808,7 +805,7 @@ "i" (Create_Dirty_Excl_SD)); } -static void r4k_copy_page_s128(unsigned long to, unsigned long from) +static void r4k_copy_page_s128(void * to, void * from) { unsigned long dummy1, dummy2; unsigned long reg1, reg2, reg3, reg4; @@ -1742,7 +1739,7 @@ * If ownes no valid ASID yet, cannot possibly have gotten * this page into the cache. */ - if(mm->context == 0) + if (mm->context == 0) return; #ifdef DEBUG_CACHE @@ -1926,7 +1923,7 @@ * If the page isn't marked valid, the page cannot possibly be * in the cache. */ - if(!(pte_val(*ptep) & _PAGE_PRESENT)) + if (!(pte_val(*ptep) & _PAGE_PRESENT)) goto out; text = (vma->vm_flags & VM_EXEC); @@ -1936,7 +1933,7 @@ * 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->mm) && (pte_val(*ptep) & _PAGE_VALID)) { + if((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) { blast_dcache32_page(page); if(text) blast_icache32_page(page); @@ -1965,110 +1962,119 @@ * flush. * 3) In KSEG1, no flush necessary. */ -static void r4k_flush_page_to_ram_s16d16i16(unsigned long page) +static void r4k_flush_page_to_ram_s16d16i16(struct page * page) { - page &= PAGE_MASK; - if((page >= KSEG0 && page < KSEG1) || (page >= KSEG2)) { + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { #ifdef DEBUG_CACHE - printk("cram[%08lx]", page); + printk("cram[%08lx]", addr); #endif - blast_scache16_page(page); + blast_scache16_page(addr); } } -static void r4k_flush_page_to_ram_s32d16i16(unsigned long page) +static void r4k_flush_page_to_ram_s32d16i16(struct page * page) { - page &= PAGE_MASK; - if((page >= KSEG0 && page < KSEG1) || (page >= KSEG2)) { + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { #ifdef DEBUG_CACHE - printk("cram[%08lx]", page); + printk("cram[%08lx]", addr); #endif - blast_scache32_page(page); + blast_scache32_page(addr); } } -static void r4k_flush_page_to_ram_s64d16i16(unsigned long page) +static void r4k_flush_page_to_ram_s64d16i16(struct page * page) { - page &= PAGE_MASK; - if((page >= KSEG0 && page < KSEG1) || (page >= KSEG2)) { + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { #ifdef DEBUG_CACHE - printk("cram[%08lx]", page); + printk("cram[%08lx]", addr); #endif - blast_scache64_page(page); + blast_scache64_page(addr); } } -static void r4k_flush_page_to_ram_s128d16i16(unsigned long page) +static void r4k_flush_page_to_ram_s128d16i16(struct page * page) { - page &= PAGE_MASK; - if((page >= KSEG0 && page < KSEG1) || (page >= KSEG2)) { + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { #ifdef DEBUG_CACHE - printk("cram[%08lx]", page); + printk("cram[%08lx]", addr); #endif - blast_scache128_page(page); + blast_scache128_page(addr); } } -static void r4k_flush_page_to_ram_s32d32i32(unsigned long page) +static void r4k_flush_page_to_ram_s32d32i32(struct page * page) { - page &= PAGE_MASK; - if((page >= KSEG0 && page < KSEG1) || (page >= KSEG2)) { + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { #ifdef DEBUG_CACHE - printk("cram[%08lx]", page); + printk("cram[%08lx]", addr); #endif - blast_scache32_page(page); + blast_scache32_page(addr); } } -static void r4k_flush_page_to_ram_s64d32i32(unsigned long page) +static void r4k_flush_page_to_ram_s64d32i32(struct page * page) { - page &= PAGE_MASK; - if((page >= KSEG0 && page < KSEG1) || (page >= KSEG2)) { + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { #ifdef DEBUG_CACHE - printk("cram[%08lx]", page); + printk("cram[%08lx]", addr); #endif - blast_scache64_page(page); + blast_scache64_page(addr); } } -static void r4k_flush_page_to_ram_s128d32i32(unsigned long page) +static void r4k_flush_page_to_ram_s128d32i32(struct page * page) { - page &= PAGE_MASK; - if((page >= KSEG0 && page < KSEG1) || (page >= KSEG2)) { + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { #ifdef DEBUG_CACHE - printk("cram[%08lx]", page); + printk("cram[%08lx]", addr); #endif - blast_scache128_page(page); + blast_scache128_page(addr); } } -static void r4k_flush_page_to_ram_d16i16(unsigned long page) +static void r4k_flush_page_to_ram_d16i16(struct page * page) { - page &= PAGE_MASK; - if((page >= KSEG0 && page < KSEG1) || (page >= KSEG2)) { + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { unsigned long flags; #ifdef DEBUG_CACHE - printk("cram[%08lx]", page); + printk("cram[%08lx]", addr); #endif - save_and_cli(flags); - blast_dcache16_page(page); - restore_flags(flags); + __save_and_cli(flags); + blast_dcache16_page(addr); + __restore_flags(flags); } } -static void r4k_flush_page_to_ram_d32i32(unsigned long page) +static void r4k_flush_page_to_ram_d32i32(struct page * page) { - page &= PAGE_MASK; - if((page >= KSEG0 && page < KSEG1) || (page >= KSEG2)) { + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { unsigned long flags; #ifdef DEBUG_CACHE - printk("cram[%08lx]", page); + printk("cram[%08lx]", addr); #endif - save_and_cli(flags); - blast_dcache32_page(page); - restore_flags(flags); + __save_and_cli(flags); + blast_dcache32_page(addr); + __restore_flags(flags); } } @@ -2202,7 +2208,7 @@ unsigned int flags; daddr = addr & ~(dc_lsize - 1); - save_and_cli(flags); + __save_and_cli(flags); /* Clear internal cache refill buffer */ *(volatile unsigned int *)KSEG1; @@ -2212,7 +2218,7 @@ iaddr = addr & ~(ic_lsize - 1); protected_flush_icache_line(iaddr); protected_flush_icache_line(iaddr + ic_lsize); - restore_flags(flags); + __restore_flags(flags); } #undef DEBUG_TLB @@ -2222,7 +2228,7 @@ #define NTLB_ENTRIES_HALF 24 /* Fixed on all R4XX0 variants... */ -static inline void r4k_flush_tlb_all(void) +void flush_tlb_all(void) { unsigned long flags; unsigned long old_ctx; @@ -2255,7 +2261,7 @@ restore_flags(flags); } -static void r4k_flush_tlb_mm(struct mm_struct *mm) +void flush_tlb_mm(struct mm_struct *mm) { if(mm->context != 0) { unsigned long flags; @@ -2271,7 +2277,7 @@ } } -static void r4k_flush_tlb_range(struct mm_struct *mm, unsigned long start, +void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { if(mm->context != 0) { @@ -2320,7 +2326,7 @@ } } -static void r4k_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { if(vma->vm_mm->context != 0) { unsigned long flags; @@ -2354,11 +2360,11 @@ } /* Load a new root pointer into the TLB. */ -static void r4k_load_pgd(unsigned long pg_dir) +void load_pgd(unsigned long pg_dir) { } -static void r4k_pgd_init(unsigned long page) +void pgd_init(unsigned long page) { unsigned long *p = (unsigned long *) page; int i; @@ -2385,7 +2391,7 @@ * 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. */ -static void r4k_update_mmu_cache(struct vm_area_struct * vma, +void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { unsigned long flags; @@ -2394,7 +2400,7 @@ pte_t *ptep; int idx, pid; - pid = (get_entryhi() & 0xff); + pid = get_entryhi() & 0xff; #ifdef DEBUG_TLB if((pid != (vma->vm_mm->context & 0xff)) || (vma->vm_mm->context == 0)) { @@ -2459,7 +2465,7 @@ } #endif -static void r4k_show_regs(struct pt_regs * regs) +void show_regs(struct pt_regs * regs) { /* Saved main processor registers. */ printk("$0 : %08lx %08lx %08lx %08lx\n", @@ -2484,7 +2490,7 @@ regs->cp0_epc, regs->cp0_status, regs->cp0_cause); } -static void r4k_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, +void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask) { unsigned long flags; @@ -2630,36 +2636,36 @@ 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_d16i16; + _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_d16i16; 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; + _clear_page = r4k_clear_page_r4600_v1; + _copy_page = r4k_copy_page_r4600_v1; } else if (prid == 0x2020) { /* R4600 V2.0 */ - clear_page = r4k_clear_page_r4600_v2; - copy_page = r4k_copy_page_r4600_v2; + _clear_page = r4k_clear_page_r4600_v2; + _copy_page = r4k_copy_page_r4600_v2; } else { - clear_page = r4k_clear_page_d32; - copy_page = r4k_copy_page_d32; + _clear_page = r4k_clear_page_d32; + _copy_page = r4k_copy_page_d32; } - flush_cache_all = r4k_flush_cache_all_d32i32; - flush_cache_mm = r4k_flush_cache_mm_d32i32; - flush_cache_range = r4k_flush_cache_range_d32i32; - flush_cache_page = r4k_flush_cache_page_d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_d32i32; + _flush_cache_all = r4k_flush_cache_all_d32i32; + _flush_cache_mm = r4k_flush_cache_mm_d32i32; + _flush_cache_range = r4k_flush_cache_range_d32i32; + _flush_cache_page = r4k_flush_cache_page_d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_d32i32; break; } - 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; + _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) @@ -2668,82 +2674,82 @@ 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; - flush_page_to_ram = r4k_flush_page_to_ram_s16d16i16; + _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; + _flush_page_to_ram = r4k_flush_page_to_ram_s16d16i16; break; case 32: panic("Invalid cache configuration detected"); }; - clear_page = r4k_clear_page_s16; - copy_page = r4k_copy_page_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; - flush_page_to_ram = r4k_flush_page_to_ram_s32d16i16; + _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; + _flush_page_to_ram = r4k_flush_page_to_ram_s32d16i16; break; case 32: - flush_cache_all = r4k_flush_cache_all_s32d32i32; - flush_cache_mm = r4k_flush_cache_mm_s32d32i32; - flush_cache_range = r4k_flush_cache_range_s32d32i32; - flush_cache_page = r4k_flush_cache_page_s32d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_s32d32i32; + _flush_cache_all = r4k_flush_cache_all_s32d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s32d32i32; + _flush_cache_range = r4k_flush_cache_range_s32d32i32; + _flush_cache_page = r4k_flush_cache_page_s32d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s32d32i32; break; }; - clear_page = r4k_clear_page_s32; - copy_page = r4k_copy_page_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; - flush_page_to_ram = r4k_flush_page_to_ram_s64d16i16; + _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; + _flush_page_to_ram = r4k_flush_page_to_ram_s64d16i16; break; case 32: - flush_cache_all = r4k_flush_cache_all_s64d32i32; - flush_cache_mm = r4k_flush_cache_mm_s64d32i32; - flush_cache_range = r4k_flush_cache_range_s64d32i32; - flush_cache_page = r4k_flush_cache_page_s64d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_s64d32i32; + _flush_cache_all = r4k_flush_cache_all_s64d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s64d32i32; + _flush_cache_range = r4k_flush_cache_range_s64d32i32; + _flush_cache_page = r4k_flush_cache_page_s64d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s64d32i32; break; }; - clear_page = r4k_clear_page_s64; - copy_page = r4k_copy_page_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; - flush_page_to_ram = r4k_flush_page_to_ram_s128d16i16; + _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; + _flush_page_to_ram = r4k_flush_page_to_ram_s128d16i16; break; case 32: - flush_cache_all = r4k_flush_cache_all_s128d32i32; - flush_cache_mm = r4k_flush_cache_mm_s128d32i32; - flush_cache_range = r4k_flush_cache_range_s128d32i32; - flush_cache_page = r4k_flush_cache_page_s128d32i32; - flush_page_to_ram = r4k_flush_page_to_ram_s128d32i32; + _flush_cache_all = r4k_flush_cache_all_s128d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s128d32i32; + _flush_cache_range = r4k_flush_cache_range_s128d32i32; + _flush_cache_page = r4k_flush_cache_page_s128d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s128d32i32; break; }; - clear_page = r4k_clear_page_s128; - copy_page = r4k_copy_page_s128; + _clear_page = r4k_clear_page_s128; + _copy_page = r4k_copy_page_s128; break; } - 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; + _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); @@ -2765,11 +2771,6 @@ setup_noscache_funcs(); } -static int r4k_user_mode(struct pt_regs *regs) -{ - return (regs->cp0_status & ST0_KSU) == KSU_USER; -} - void __init ld_mmu_r4xx0(void) { unsigned long config = read_32bit_cp0_register(CP0_CONFIG); @@ -2787,29 +2788,13 @@ case CPU_R4700: case CPU_R5000: case CPU_NEVADA: - flush_cache_page = r4k_flush_cache_page_d32i32_r4600; + _flush_cache_page = r4k_flush_cache_page_d32i32_r4600; } - flush_cache_sigtramp = r4k_flush_cache_sigtramp; + _flush_cache_sigtramp = r4k_flush_cache_sigtramp; if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) { - flush_cache_sigtramp = r4600v20k_flush_cache_sigtramp; + _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; - r4xx0_asid_setup(); - - load_pgd = r4k_load_pgd; - pgd_init = r4k_pgd_init; - update_mmu_cache = r4k_update_mmu_cache; - - show_regs = r4k_show_regs; - - add_wired_entry = r4k_add_wired_entry; - - user_mode = r4k_user_mode; flush_cache_all(); write_32bit_cp0_register(CP0_WIRED, 0); diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/r6000.c linux/arch/mips/mm/r6000.c --- v2.3.47/linux/arch/mips/mm/r6000.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/mm/r6000.c Wed Dec 31 16:00:00 1969 @@ -1,199 +0,0 @@ -/* $Id: r6000.c,v 1.6 1999/01/04 16:03:54 ralf Exp $ - * - * r6000.c: MMU and cache routines for the R6000 processors. - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -__asm__(".set mips3"); /* because we know... */ - -/* Cache operations. XXX Write these dave... */ -static inline void r6000_flush_cache_all(void) -{ - /* XXX */ -} - -static void r6000_flush_cache_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -static void r6000_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -static void r6000_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ - /* XXX */ -} - -static void r6000_flush_page_to_ram(unsigned long page) -{ - /* XXX */ -} - -static void r6000_flush_cache_sigtramp(unsigned long page) -{ - /* XXX */ -} - -/* TLB operations. XXX Write these dave... */ -static inline void r6000_flush_tlb_all(void) -{ - /* XXX */ -} - -static void r6000_flush_tlb_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -static void r6000_flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -static void r6000_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - /* XXX */ -} - -static void r6000_load_pgd(unsigned long pg_dir) -{ -} - -static void r6000_pgd_init(unsigned long page) -{ - unsigned long dummy1, dummy2; - - /* - * This version is optimized for the R6000. We generate dirty lines - * in the datacache, overwrite these lines with zeros and then flush - * the cache. Sounds horribly complicated but is just a trick to - * avoid unnecessary loads of from memory and uncached stores which - * are very expensive. Not tested yet as the R6000 is a rare CPU only - * available in SGI machines and I don't have one. - */ - __asm__ __volatile__( - ".set\tnoreorder\n" - "1:\t" - "cache\t%5,(%0)\n\t" - "sw\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" - "cache\t%5,16(%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), - "i" (Create_Dirty_Excl_D)); -} - -static void r6000_update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) -{ - r6000_flush_tlb_page(vma, address); - /* - * FIXME: We should also reload a new entry into the TLB to - * avoid unnecessary exceptions. - */ -} - -static void r6000_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\nStatus: %08x\nCause : %08x\n", - (unsigned long) regs->cp0_epc, (unsigned int) regs->cp0_status, - (unsigned int) regs->cp0_cause); -} - -static void r6000_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - /* XXX */ -} - -static int r6000_user_mode(struct pt_regs *regs) -{ - return !(regs->cp0_status & 0x4); -} - -void __init ld_mmu_r6000(void) -{ - flush_cache_all = r6000_flush_cache_all; - flush_cache_mm = r6000_flush_cache_mm; - flush_cache_range = r6000_flush_cache_range; - flush_cache_page = r6000_flush_cache_page; - flush_cache_sigtramp = r6000_flush_cache_sigtramp; - flush_page_to_ram = r6000_flush_page_to_ram; - - flush_tlb_all = r6000_flush_tlb_all; - flush_tlb_mm = r6000_flush_tlb_mm; - flush_tlb_range = r6000_flush_tlb_range; - flush_tlb_page = r6000_flush_tlb_page; - r6000_asid_setup(); - - load_pgd = r6000_load_pgd; - pgd_init = r6000_pgd_init; - update_mmu_cache = r6000_update_mmu_cache; - - show_regs = r6000_show_regs; - - add_wired_entry = r6000_add_wired_entry; - - user_mode = r6000_user_mode; - - flush_cache_all(); - flush_tlb_all(); -} diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/tfp.c linux/arch/mips/mm/tfp.c --- v2.3.47/linux/arch/mips/mm/tfp.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/mm/tfp.c Wed Dec 31 16:00:00 1969 @@ -1,120 +0,0 @@ -/* $Id: tfp.c,v 1.6 1999/01/04 16:03:55 ralf Exp $ - * - * tfp.c: MMU and cache routines specific to the r8000 (TFP). - * - * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -extern unsigned long mips_tlb_entries; - -/* Cache operations. XXX Write these dave... */ -static inline void tfp_flush_cache_all(void) -{ - /* XXX */ -} - -static void tfp_flush_cache_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -static void tfp_flush_cache_range(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -static void tfp_flush_cache_page(struct vm_area_struct *vma, - unsigned long page) -{ - /* XXX */ -} - -static void tfp_flush_page_to_ram(unsigned long page) -{ - /* XXX */ -} - -static void tfp_flush_cache_sigtramp(unsigned long page) -{ - /* XXX */ -} - -/* TLB operations. XXX Write these dave... */ -static inline void tfp_flush_tlb_all(void) -{ - /* XXX */ -} - -static void tfp_flush_tlb_mm(struct mm_struct *mm) -{ - /* XXX */ -} - -static void tfp_flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long end) -{ - /* XXX */ -} - -static void tfp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) -{ - /* XXX */ -} - -static void tfp_load_pgd(unsigned long pg_dir) -{ -} - -static void tfp_pgd_init(unsigned long page) -{ -} - -static void tfp_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, - unsigned long entryhi, unsigned long pagemask) -{ - /* XXX */ -} - -static int tfp_user_mode(struct pt_regs *regs) -{ - return (regs->cp0_status & ST0_KSU) == KSU_USER; -} - -void __init ld_mmu_tfp(void) -{ - flush_cache_all = tfp_flush_cache_all; - flush_cache_mm = tfp_flush_cache_mm; - flush_cache_range = tfp_flush_cache_range; - flush_cache_page = tfp_flush_cache_page; - flush_cache_sigtramp = tfp_flush_cache_sigtramp; - flush_page_to_ram = tfp_flush_page_to_ram; - - flush_tlb_all = tfp_flush_tlb_all; - flush_tlb_mm = tfp_flush_tlb_mm; - flush_tlb_range = tfp_flush_tlb_range; - flush_tlb_page = tfp_flush_tlb_page; - tfp_asid_setup(); - - add_wired_entry = tfp_add_wired_entry; - - user_mode = tfp_user_mode; - - load_pgd = tfp_load_pgd; - pgd_init = tfp_pgd_init; - - flush_cache_all(); - flush_tlb_all(); -} diff -u --recursive --new-file v2.3.47/linux/arch/mips/mm/umap.c linux/arch/mips/mm/umap.c --- v2.3.47/linux/arch/mips/mm/umap.c Sat Aug 16 09:51:07 1997 +++ linux/arch/mips/mm/umap.c Thu Feb 24 22:52:30 2000 @@ -26,7 +26,7 @@ #include #include -#include +#include #include static inline void @@ -114,16 +114,16 @@ static inline void free_pte(pte_t page) { if (pte_present(page)) { - unsigned long addr = pte_page(page); - if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr))) + unsigned long nr = pte_pagenr(page); + if (nr >= max_mapnr || PageReserved(mem_map+nr)) return; - free_page(addr); + __free_page(pte_page(page)); if (current->mm->rss <= 0) return; current->mm->rss--; return; } - swap_free(pte_val(page)); + swap_free(pte_to_swp_entry(page)); } static inline void forget_pte(pte_t page) @@ -152,15 +152,15 @@ end = PMD_SIZE; do { pte_t oldpage = *pte; - unsigned long page; + struct page * page; pte_clear(pte); vdir = pgd_offset_k (vaddr); vpmd = pmd_offset (vdir, vaddr); vpte = pte_offset (vpmd, vaddr); page = pte_page (*vpte); - - set_pte(pte, mk_pte_phys(page, PAGE_USERIO)); + + set_pte(pte, mk_pte(page, PAGE_USERIO)); forget_pte(oldpage); address += PAGE_SIZE; vaddr += PAGE_SIZE; diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/Makefile linux/arch/mips/sgi/kernel/Makefile --- v2.3.47/linux/arch/mips/sgi/kernel/Makefile Mon Dec 20 18:48:21 1999 +++ linux/arch/mips/sgi/kernel/Makefile Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.7 1999/05/07 18:00:16 ulfc Exp $ +# $Id: Makefile,v 1.8 2000/02/05 06:47:08 ralf Exp $ # Makefile for the SGI specific kernel interface routines # under Linux. # diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/indyIRQ.S linux/arch/mips/sgi/kernel/indyIRQ.S --- v2.3.47/linux/arch/mips/sgi/kernel/indyIRQ.S Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sgi/kernel/indyIRQ.S Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: indyIRQ.S,v 1.3 1998/03/22 23:27:17 ralf Exp $ +/* $Id: indyIRQ.S,v 1.4 1999/08/18 23:37:45 ralf Exp $ * indyIRQ.S: Interrupt exception dispatch code for FullHouse and * Guiness. * @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/indy_hpc.c linux/arch/mips/sgi/kernel/indy_hpc.c --- v2.3.47/linux/arch/mips/sgi/kernel/indy_hpc.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/sgi/kernel/indy_hpc.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: indy_hpc.c,v 1.6 1999/05/07 22:34:31 ulfc Exp $ +/* $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. * @@ -8,8 +8,8 @@ #include #include -#include -#include +#include +#include #include /* #define DEBUG_SGIHPC */ @@ -18,7 +18,7 @@ struct hpc3_miscregs *hpc3mregs; /* We need software copies of these because they are write only. */ -unsigned long sgi_hpc_write1, sgi_hpc_write2; +unsigned int sgi_hpc_write1, sgi_hpc_write2; /* Machine specific identifier knobs. */ int sgi_has_ioc2 = 0; diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/indy_int.c linux/arch/mips/sgi/kernel/indy_int.c --- v2.3.47/linux/arch/mips/sgi/kernel/indy_int.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/sgi/kernel/indy_int.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: indy_int.c,v 1.13 1999/06/12 17:26:15 ulfc Exp $ +/* $Id: indy_int.c,v 1.17 2000/02/04 07:40:23 ralf Exp $ * * indy_int.c: Routines for generic manipulation of the INT[23] ASIC * found on INDY workstations.. @@ -9,7 +9,9 @@ * - Indigo2 changes * - Interrupt handling fixes */ +#include #include + #include #include #include @@ -32,9 +34,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -257,8 +259,6 @@ 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 @@ -272,7 +272,7 @@ int do_random, cpu; cpu = smp_processor_id(); - hardirq_enter(cpu); + irq_enter(cpu); kstat.irqs[0][irq]++; printk("Got irq %d, press a key.", irq); @@ -308,7 +308,7 @@ add_interrupt_randomness(irq); __cli(); } - hardirq_exit(cpu); + irq_exit(cpu); /* unmasking and bottom half handling is done magically for us. */ } @@ -451,10 +451,10 @@ /* if action == NULL, then we do have a handler for the irq */ if ( action == NULL ) { goto no_handler; } - hardirq_enter(cpu); + irq_enter(cpu); kstat.irqs[0][irq + 16]++; action->handler(irq, action->dev_id, regs); - hardirq_exit(cpu); + irq_exit(cpu); goto end; no_handler: @@ -489,10 +489,10 @@ /* if action == NULL, then we do have a handler for the irq */ if ( action == NULL ) { goto no_handler; } - hardirq_enter(cpu); + irq_enter(cpu); kstat.irqs[0][irq + 24]++; action->handler(irq, action->dev_id, regs); - hardirq_exit(cpu); + irq_exit(cpu); goto end; no_handler: @@ -507,13 +507,13 @@ int cpu = smp_processor_id(); int irq = 6; - hardirq_enter(cpu); + irq_enter(cpu); kstat.irqs[0][irq]++; printk("Got a bus error IRQ, shouldn't happen yet\n"); show_regs(regs); printk("Spinning...\n"); while(1); - hardirq_exit(cpu); + irq_exit(cpu); } /* Misc. crap just to keep the kernel linking... */ diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/indy_mc.c linux/arch/mips/sgi/kernel/indy_mc.c --- v2.3.47/linux/arch/mips/sgi/kernel/indy_mc.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/sgi/kernel/indy_mc.c Thu Feb 24 22:52:30 2000 @@ -4,21 +4,21 @@ * 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.4 1999/05/07 22:34:32 ulfc Exp $ + * $Id: indy_mc.c,v 1.8 1999/12/06 23:13:20 ralf Exp $ */ #include #include #include #include -#include -#include +#include +#include #include /* #define DEBUG_SGIMC */ struct sgimc_misc_ctrl *mcmisc_regs; -unsigned long *rpsscounter; +u32 *rpsscounter; struct sgimc_dma_ctrl *dmactrlregs; static inline char *mconfig_string(unsigned long val) @@ -52,7 +52,7 @@ unsigned long tmpreg; mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000); - rpsscounter = (unsigned long *) (KSEG1 + 0x1fa01004); + rpsscounter = (unsigned int *) (KSEG1 + 0x1fa01004); dmactrlregs = (struct sgimc_dma_ctrl *) (KSEG1+0x1fa02000); printk("MC: SGI memory controller Revision %d\n", diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/indy_rtc.c linux/arch/mips/sgi/kernel/indy_rtc.c --- v2.3.47/linux/arch/mips/sgi/kernel/indy_rtc.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/sgi/kernel/indy_rtc.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: indy_rtc.c,v 1.1 1998/06/25 20:19:17 ralf Exp $ +/* $Id: indy_rtc.c,v 1.2 1999/10/21 00:23:05 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -9,7 +9,7 @@ * Copyright (C) 1998 by Ralf Baechle */ #include -#include +#include static unsigned char indy_rtc_read_data(unsigned long addr) { diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c --- v2.3.47/linux/arch/mips/sgi/kernel/indy_sc.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/sgi/kernel/indy_sc.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: indy_sc.c,v 1.9 1999/05/12 21:57:49 ulfc Exp $ +/* $Id: indy_sc.c,v 1.13 1999/12/04 03:59:00 ralf Exp $ * * indy_sc.c: Indy cache managment functions. * @@ -11,8 +11,8 @@ #include #include -#include -#include +#include +#include #include #include #include @@ -221,6 +221,7 @@ void __init indy_sc_init(void) { +return; if (indy_sc_probe()) { indy_sc_enable(); bcops = &indy_sc_ops; diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/indy_timer.c linux/arch/mips/sgi/kernel/indy_timer.c --- v2.3.47/linux/arch/mips/sgi/kernel/indy_timer.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/sgi/kernel/indy_timer.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: indy_timer.c,v 1.12 1999/06/13 16:30:36 ralf Exp $ +/* $Id: indy_timer.c,v 1.18 2000/02/04 07:40:23 ralf Exp $ * * indy_timer.c: Setting up the clock on the INDY 8254 controller. * @@ -21,10 +21,10 @@ #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 @@ -33,6 +33,8 @@ 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); @@ -85,6 +87,7 @@ 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. */ @@ -107,11 +110,14 @@ 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 - last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + 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; + } + write_unlock(&xtime_lock); } static unsigned long dosample(volatile unsigned char *tcwp, @@ -252,9 +258,10 @@ set_cp0_status(ST0_IM, ALLINTS); sti(); - /* Read time from the dallas chipset. */ - xtime.tv_sec = get_indy_time(); + 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) @@ -262,29 +269,29 @@ int cpu = smp_processor_id(); int irq = 4; - hardirq_enter(cpu); + irq_enter(cpu); kstat.irqs[0][irq]++; printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n"); prom_getchar(); prom_imode(); - hardirq_exit(cpu); + irq_exit(cpu); } void do_gettimeofday(struct timeval *tv) { unsigned long flags; - save_and_cli(flags); + read_lock_irqsave(&xtime_lock, flags); *tv = xtime; - restore_flags(flags); + read_unlock_irqrestore(&xtime_lock, flags); } void do_settimeofday(struct timeval *tv) { - cli(); + write_lock_irq(&xtime_lock); xtime = *tv; time_state = TIME_BAD; time_maxerror = MAXPHASE; time_esterror = MAXPHASE; - sti(); + write_unlock_irq(&xtime_lock); } diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/reset.c linux/arch/mips/sgi/kernel/reset.c --- v2.3.47/linux/arch/mips/sgi/kernel/reset.c Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sgi/kernel/reset.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: reset.c,v 1.6 1999/04/10 12:21:30 ulfc Exp $ +/* $Id: reset.c,v 1.8 1999/10/21 00:23:05 ralf Exp $ * * Reset a SGI. * @@ -17,8 +17,8 @@ #include #include #include -#include -#include +#include +#include /* * Just powerdown if init hasn't done after POWERDOWN_TIMEOUT seconds. @@ -108,7 +108,7 @@ if (has_paniced) prom_reboot(); - enable_irq(9); + enable_irq(SGI_PANEL_IRQ); } static inline void power_button(void) @@ -185,7 +185,7 @@ hpc3mregs->panel = 3; /* power_interrupt | power_supply_on */ if (ioc_icontrol->istat1 & 2) { /* Wait until interrupt goes away */ - disable_irq(9); + disable_irq(SGI_PANEL_IRQ); init_timer(&debounce_timer); debounce_timer.function = debounce; debounce_timer.expires = jiffies + 5; @@ -239,7 +239,7 @@ _machine_halt = sgi_machine_halt; _machine_power_off = sgi_machine_power_off; - request_irq(9, panel_int, 0, "Front Panel", NULL); + 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 -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/setup.c linux/arch/mips/sgi/kernel/setup.c --- v2.3.47/linux/arch/mips/sgi/kernel/setup.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/sgi/kernel/setup.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.24 1999/06/12 17:26:15 ulfc Exp $ +/* $Id: setup.c,v 1.29 2000/01/27 01:05:23 ralf Exp $ * * setup.c: SGI specific setup, including init of the feature struct. * @@ -22,10 +22,9 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include #include #ifdef CONFIG_REMOTE_DEBUG @@ -34,7 +33,7 @@ #endif #if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE) -extern void console_setup(char *, int *); +extern void console_setup(char *); #endif extern struct rtc_ops indy_rtc_ops; @@ -129,6 +128,15 @@ #endif } +int __init page_is_ram(unsigned long pagenr) +{ + if (pagenr < MAP_NR(PAGE_OFFSET + 0x2000UL)) + return 1; + if (pagenr > MAP_NR(PAGE_OFFSET + 0x08002000)) + return 1; + return 0; +} + void __init sgi_setup(void) { #ifdef CONFIG_SERIAL_CONSOLE @@ -161,9 +169,9 @@ ctype = prom_getenv("console"); if(*ctype == 'd') { if(*(ctype+1)=='2') - console_setup ("ttyS1", NULL); + console_setup ("ttyS1"); else - console_setup ("ttyS0", NULL); + console_setup ("ttyS0"); } #endif @@ -197,6 +205,18 @@ #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 diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/system.c linux/arch/mips/sgi/kernel/system.c --- v2.3.47/linux/arch/mips/sgi/kernel/system.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/sgi/kernel/system.c Thu Feb 24 22:52:30 2000 @@ -3,14 +3,14 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * - * $Id: system.c,v 1.7 1998/10/18 22:55:34 tsbogend Exp $ + * $Id: system.c,v 1.9 1999/10/21 00:23:05 ralf Exp $ */ #include #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/sgi/kernel/time.c linux/arch/mips/sgi/kernel/time.c --- v2.3.47/linux/arch/mips/sgi/kernel/time.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/sgi/kernel/time.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.2 1998/04/05 11:24:00 ralf Exp $ +/* $Id: time.c,v 1.3 1999/10/09 00:00:59 ralf Exp $ * time.c: Generic SGI time_init() code, this will dispatch to the * appropriate per-architecture time/counter init code. * diff -u --recursive --new-file v2.3.47/linux/arch/mips/sni/Makefile linux/arch/mips/sni/Makefile --- v2.3.47/linux/arch/mips/sni/Makefile Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sni/Makefile Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 1999/01/04 16:03:57 ralf Exp $ +# $Id: Makefile,v 1.4 2000/02/18 00:24:30 ralf Exp $ # # Makefile for the SNI specific part of the kernel # @@ -14,7 +14,7 @@ all: sni.o O_TARGET := sni.o -O_OBJS := int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o +O_OBJS := dma.o int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o int-handler.o: int-handler.S diff -u --recursive --new-file v2.3.47/linux/arch/mips/sni/dma.c linux/arch/mips/sni/dma.c --- v2.3.47/linux/arch/mips/sni/dma.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips/sni/dma.c Thu Feb 24 22:52:30 2000 @@ -0,0 +1,42 @@ +/* $Id: dma.c,v 1.2 2000/02/24 00:12:41 ralf Exp $ + * + * Dynamic DMA mapping support. + * + * On RM200 there is no hardware dynamic DMA address translation, + * so consistent alloc/free are merely page allocation/freeing. + * The rest of the dynamic DMA mapping interface is implemented + * in . + * + * These routines assume that the RM has all it's memory at physical + * addresses of < 512mb. + */ +#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; + int order = get_order(size); + + if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + ret = (void *)__get_free_pages(gfp, order); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + dma_cache_wback_inv(ret, PAGE_SIZE << order); + return KSEG1ADDR(ret); +} + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, get_order(size)); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips/sni/int-handler.S linux/arch/mips/sni/int-handler.S --- v2.3.47/linux/arch/mips/sni/int-handler.S Fri Jun 25 17:40:13 1999 +++ linux/arch/mips/sni/int-handler.S Thu Feb 24 22:52:30 2000 @@ -1,11 +1,10 @@ -/* $Id: int-handler.S,v 1.4 1999/01/04 16:03:58 ralf Exp $ +/* $Id: int-handler.S,v 1.5 1999/08/18 23:37:46 ralf Exp $ * * SNI RM200 PCI specific interrupt handler code. * * Copyright (C) 1994 - 1997 by Ralf Baechle */ #include -#include #include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/sni/io.c linux/arch/mips/sni/io.c --- v2.3.47/linux/arch/mips/sni/io.c Fri Sep 10 23:57:27 1999 +++ linux/arch/mips/sni/io.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: io.c,v 1.3 1999/01/04 16:03:58 ralf Exp $ +/* $Id: io.c,v 1.5 1999/10/09 00:00:59 ralf Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -8,7 +8,6 @@ */ #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.47/linux/arch/mips/sni/pci.c linux/arch/mips/sni/pci.c --- v2.3.47/linux/arch/mips/sni/pci.c Thu Jan 6 12:57:47 2000 +++ linux/arch/mips/sni/pci.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: pci.c,v 1.7 1999/01/04 16:03:58 ralf Exp $ +/* $Id: pci.c,v 1.10 2000/02/05 06:47:09 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 @@ -6,7 +6,7 @@ * * SNI specific PCI support for RM200/RM300. * - * Copyright (C) 1997, 1998 Ralf Baechle + * Copyright (C) 1997, 1998, 1999 Ralf Baechle */ #include #include @@ -17,16 +17,18 @@ #ifdef CONFIG_PCI -#define mkaddr(bus, dev_fn, where) \ +#define mkaddr(dev, where) \ do { \ - if (bus == 0 && dev_fn >= PCI_DEVFN(8, 0)) \ + if ((dev)->bus->number == 0) \ return -1; \ - *(volatile u32 *)PCIMT_CONFIG_ADDRESS = ((bus & 0xff) << 0x10) | \ - ((dev_fn & 0xff) << 0x08) | \ - (where & 0xfc); \ + *(volatile u32 *)PCIMT_CONFIG_ADDRESS = \ + ((dev->bus->number & 0xff) << 0x10) | \ + ((dev->dev_fn & 0xff) << 0x08) | \ + (where & 0xfc); \ } while(0); -static void sni_rm200_pcibios_fixup (void) +/* To do: Bring this uptodate ... */ +static void pcimt_pcibios_fixup (void) { struct pci_dev *dev; @@ -65,14 +67,12 @@ * 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 sni_rm200_pcibios_read_config_byte (unsigned char bus, - unsigned char dev_fn, - unsigned char where, - unsigned char *val) +static int pcimt_read_config_byte (struct pci_dev *dev, + int where, unsigned char *val) { u32 res; - mkaddr(bus, dev_fn, where); + mkaddr(dev, where); res = *(volatile u32 *)PCIMT_CONFIG_DATA; res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xff; *val = res; @@ -80,16 +80,14 @@ return PCIBIOS_SUCCESSFUL; } -static int sni_rm200_pcibios_read_config_word (unsigned char bus, - unsigned char dev_fn, - unsigned char where, - unsigned short *val) +static int pcimt_read_config_word (struct pci_dev *dev, + int where, unsigned short *val) { u32 res; if (where & 1) return PCIBIOS_BAD_REGISTER_NUMBER; - mkaddr(bus, dev_fn, where); + mkaddr(dev, where); res = *(volatile u32 *)PCIMT_CONFIG_DATA; res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xffff; *val = res; @@ -97,16 +95,14 @@ return PCIBIOS_SUCCESSFUL; } -static int sni_rm200_pcibios_read_config_dword (unsigned char bus, - unsigned char dev_fn, - unsigned char where, - unsigned int *val) +static int pcimt_read_config_dword (struct pci_dev *dev, + int where, unsigned int *val) { u32 res; if (where & 3) return PCIBIOS_BAD_REGISTER_NUMBER; - mkaddr(bus, dev_fn, where); + mkaddr(dev, where); res = *(volatile u32 *)PCIMT_CONFIG_DATA; res = le32_to_cpu(res); *val = res; @@ -114,51 +110,44 @@ return PCIBIOS_SUCCESSFUL; } -static int sni_rm200_pcibios_write_config_byte (unsigned char bus, - unsigned char dev_fn, - unsigned char where, - unsigned char val) +static int pcimt_write_config_byte (struct pci_dev *dev, + int where, unsigned char val) { - mkaddr(bus, dev_fn, where); + mkaddr(dev, where); *(volatile u8 *)(PCIMT_CONFIG_DATA + (where & 3)) = val; return PCIBIOS_SUCCESSFUL; } -static int sni_rm200_pcibios_write_config_word (unsigned char bus, - unsigned char dev_fn, - unsigned char where, - unsigned short val) +static int pcimt_write_config_word (struct pci_dev *dev, + int where, unsigned short val) { if (where & 1) return PCIBIOS_BAD_REGISTER_NUMBER; - mkaddr(bus, dev_fn, where); + mkaddr(dev, where); *(volatile u16 *)(PCIMT_CONFIG_DATA + (where & 3)) = le16_to_cpu(val); return PCIBIOS_SUCCESSFUL; } -static int sni_rm200_pcibios_write_config_dword (unsigned char bus, - unsigned char dev_fn, - unsigned char where, - unsigned int val) +static int pcimt_write_config_dword (struct pci_dev *dev, + int where, unsigned int val) { if (where & 3) return PCIBIOS_BAD_REGISTER_NUMBER; - mkaddr(bus, dev_fn, where); + mkaddr(dev, where); *(volatile u32 *)PCIMT_CONFIG_DATA = le32_to_cpu(val); return PCIBIOS_SUCCESSFUL; } struct pci_ops sni_pci_ops = { - sni_rm200_pcibios_fixup, - sni_rm200_pcibios_read_config_byte, - sni_rm200_pcibios_read_config_word, - sni_rm200_pcibios_read_config_dword, - sni_rm200_pcibios_write_config_byte, - sni_rm200_pcibios_write_config_word, - sni_rm200_pcibios_write_config_dword + pcimt_read_config_byte, + pcimt_read_config_word, + pcimt_read_config_dword, + pcimt_write_config_byte, + pcimt_write_config_word, + pcimt_write_config_dword }; #endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.3.47/linux/arch/mips/sni/pcimt_scache.c linux/arch/mips/sni/pcimt_scache.c --- v2.3.47/linux/arch/mips/sni/pcimt_scache.c Tue Aug 31 17:29:12 1999 +++ linux/arch/mips/sni/pcimt_scache.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: pcimt_scache.c,v 1.4 1999/01/04 16:03:59 ralf Exp $ +/* $Id: pcimt_scache.c,v 1.5 1999/10/09 00:00:59 ralf Exp $ * * arch/mips/sni/pcimt_scache.c * diff -u --recursive --new-file v2.3.47/linux/arch/mips/sni/setup.c linux/arch/mips/sni/setup.c --- v2.3.47/linux/arch/mips/sni/setup.c Sat Oct 9 11:47:50 1999 +++ linux/arch/mips/sni/setup.c Thu Feb 24 22:52:30 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.10 1999/01/04 16:03:59 ralf Exp $ +/* $Id: setup.c,v 1.14 2000/01/27 01:05:23 ralf Exp $ * * Setup pointers to hardware-dependent routines. * @@ -103,6 +103,11 @@ printk("%s.\n", boardtype); } +int __init page_is_ram(unsigned long pagenr) +{ + return 1; +} + void __init sni_rm200_pci_setup(void) { tag *atag; @@ -169,6 +174,19 @@ ide_ops = &std_ide_ops; #endif conswitchp = &vga_con; + + screen_info = (struct screen_info) { + 0, 0, /* orig-x, orig-y */ + 0, /* unused */ + 52, /* orig_video_page */ + 3, /* orig_video_mode */ + 80, /* orig_video_cols */ + 4626, 3, 9, /* unused, ega_bx, unused */ + 50, /* orig_video_lines */ + 0x22, /* orig_video_isVGA */ + 16 /* orig_video_points */ + }; + rtc_ops = &std_rtc_ops; kbd_ops = &std_kbd_ops; #ifdef CONFIG_PSMOUSE diff -u --recursive --new-file v2.3.47/linux/arch/mips/tools/offset.c linux/arch/mips/tools/offset.c --- v2.3.47/linux/arch/mips/tools/offset.c Tue Oct 20 13:52:55 1998 +++ linux/arch/mips/tools/offset.c Thu Feb 24 22:52:30 2000 @@ -1,9 +1,10 @@ -/* $Id: offset.c,v 1.10 1998/08/19 21:53:53 ralf Exp $ +/* $Id: offset.c,v 1.12 1999/10/09 00:00:59 ralf Exp $ * * offset.c: Calculate pt_regs and task_struct offsets. * * Copyright (C) 1996 David S. Miller - * Made portable by Ralf Baechle + * Copyright (C) 1997, 1998, 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. */ #include @@ -82,41 +83,48 @@ offset("#define TASK_COUNTER ", struct task_struct, counter); offset("#define TASK_PRIORITY ", struct task_struct, priority); offset("#define TASK_MM ", struct task_struct, mm); + size("#define TASK_STRUCT_SIZE ", struct task_struct); linefeed; } void output_thread_defines(void) { text("/* MIPS specific thread_struct offsets. */"); - offset("#define THREAD_REG16 ", struct task_struct, tss.reg16); - offset("#define THREAD_REG17 ", struct task_struct, tss.reg17); - offset("#define THREAD_REG18 ", struct task_struct, tss.reg18); - offset("#define THREAD_REG19 ", struct task_struct, tss.reg19); - offset("#define THREAD_REG20 ", struct task_struct, tss.reg20); - offset("#define THREAD_REG21 ", struct task_struct, tss.reg21); - offset("#define THREAD_REG22 ", struct task_struct, tss.reg22); - offset("#define THREAD_REG23 ", struct task_struct, tss.reg23); - offset("#define THREAD_REG29 ", struct task_struct, tss.reg29); - offset("#define THREAD_REG30 ", struct task_struct, tss.reg30); - offset("#define THREAD_REG31 ", struct task_struct, tss.reg31); - offset("#define THREAD_STATUS ", struct task_struct, tss.cp0_status); - offset("#define THREAD_FPU ", struct task_struct, tss.fpu); - offset("#define THREAD_BVADDR ", struct task_struct, tss.cp0_badvaddr); - offset("#define THREAD_BUADDR ", struct task_struct, tss.cp0_baduaddr); - offset("#define THREAD_ECODE ", struct task_struct, tss.error_code); - offset("#define THREAD_TRAPNO ", struct task_struct, tss.trap_no); - offset("#define THREAD_PGDIR ", struct task_struct, tss.pg_dir); - offset("#define THREAD_MFLAGS ", struct task_struct, tss.mflags); - offset("#define THREAD_CURDS ", struct task_struct, tss.current_ds); - offset("#define THREAD_TRAMP ", struct task_struct, tss.irix_trampoline); - offset("#define THREAD_OLDCTX ", struct task_struct, tss.irix_oldctx); + offset("#define THREAD_REG16 ", struct task_struct, thread.reg16); + offset("#define THREAD_REG17 ", struct task_struct, thread.reg17); + offset("#define THREAD_REG18 ", struct task_struct, thread.reg18); + offset("#define THREAD_REG19 ", struct task_struct, thread.reg19); + offset("#define THREAD_REG20 ", struct task_struct, thread.reg20); + offset("#define THREAD_REG21 ", struct task_struct, thread.reg21); + offset("#define THREAD_REG22 ", struct task_struct, thread.reg22); + offset("#define THREAD_REG23 ", struct task_struct, thread.reg23); + offset("#define THREAD_REG29 ", struct task_struct, thread.reg29); + offset("#define THREAD_REG30 ", struct task_struct, thread.reg30); + offset("#define THREAD_REG31 ", struct task_struct, thread.reg31); + offset("#define THREAD_STATUS ", struct task_struct, \ + thread.cp0_status); + offset("#define THREAD_FPU ", struct task_struct, thread.fpu); + offset("#define THREAD_BVADDR ", struct task_struct, \ + thread.cp0_badvaddr); + offset("#define THREAD_BUADDR ", struct task_struct, \ + thread.cp0_baduaddr); + offset("#define THREAD_ECODE ", struct task_struct, \ + thread.error_code); + offset("#define THREAD_TRAPNO ", struct task_struct, thread.trap_no); + offset("#define THREAD_MFLAGS ", struct task_struct, thread.mflags); + offset("#define THREAD_CURDS ", struct task_struct, \ + thread.current_ds); + offset("#define THREAD_TRAMP ", struct task_struct, \ + thread.irix_trampoline); + offset("#define THREAD_OLDCTX ", struct task_struct, \ + thread.irix_oldctx); linefeed; } void output_mm_defines(void) { text("/* Linux mm_struct offsets. */"); - offset("#define MM_COUNT ", struct mm_struct, count); + offset("#define MM_USERS ", struct mm_struct, mm_users); offset("#define MM_PGD ", struct mm_struct, pgd); offset("#define MM_CONTEXT ", struct mm_struct, context); linefeed; @@ -125,20 +133,17 @@ void output_sc_defines(void) { text("/* Linux sigcontext offsets. */"); - offset("#define SC_REGMASK ", struct sigcontext, sc_regmask); - offset("#define SC_STATUS ", struct sigcontext, sc_status); - offset("#define SC_PC ", struct sigcontext, sc_pc); offset("#define SC_REGS ", struct sigcontext, sc_regs); offset("#define SC_FPREGS ", struct sigcontext, sc_fpregs); + offset("#define SC_MDHI ", struct sigcontext, sc_mdhi); + offset("#define SC_MDLO ", struct sigcontext, sc_mdlo); + offset("#define SC_PC ", struct sigcontext, sc_pc); + offset("#define SC_STATUS ", struct sigcontext, sc_status); offset("#define SC_OWNEDFP ", struct sigcontext, sc_ownedfp); offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); offset("#define SC_FPC_EIR ", struct sigcontext, sc_fpc_eir); - offset("#define SC_SSFLAGS ", struct sigcontext, sc_ssflags); - offset("#define SC_MDHI ", struct sigcontext, sc_mdhi); - offset("#define SC_MDLO ", struct sigcontext, sc_mdlo); offset("#define SC_CAUSE ", struct sigcontext, sc_cause); offset("#define SC_BADVADDR ", struct sigcontext, sc_badvaddr); - offset("#define SC_SIGSET ", struct sigcontext, sc_sigset); linefeed; } diff -u --recursive --new-file v2.3.47/linux/arch/mips64/Makefile linux/arch/mips64/Makefile --- v2.3.47/linux/arch/mips64/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/Makefile Thu Feb 24 22:53:35 2000 @@ -0,0 +1,149 @@ +# $Id: Makefile,v 1.6 2000/01/29 01:41:59 ralf Exp $ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# 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 +# + +# +# Select the object file format to substitute into the linker script. +# +ifdef CONFIG_CPU_LITTLE_ENDIAN +tool-prefix = mips64el-linux- +else +tool-prefix = mips64-linux- +endif + +ifdef CONFIG_CROSSCOMPILE +CROSS_COMPILE = $(tool-prefix) +endif + +# +# The ELF GCC uses -G0 -mabicalls -fpic as default. We don't need PIC +# code in the kernel since it only slows down the whole thing. For the +# old GCC these options are just the defaults. At some point we might +# make use of global pointer optimizations. +# +# The DECStation requires an ECOFF kernel for remote booting, other MIPS +# machines may also. Since BFD is incredibly buggy with respect to +# crossformat linking we rely on the elf2ecoff tool for format conversion. +# +CFLAGS += -mabi=64 -G 0 -mno-abicalls -fno-pic -pipe +LINKFLAGS += -G 0 -static # -N +MODFLAGS += -mlong-calls + +ifdef CONFIG_REMOTE_DEBUG +CFLAGS := $(CFLAGS) -g +endif + +# +# CPU-dependent compiler/assembler options for optimization. +# +ifdef CONFIG_CPU_R4300 +CFLAGS := $(CFLAGS) -mcpu=r4300 -mips3 +endif +ifdef CONFIG_CPU_R4X00 +CFLAGS := $(CFLAGS) -mcpu=r4600 -mips3 +endif +ifdef CONFIG_CPU_R5000 +CFLAGS := $(CFLAGS) -mcpu=r8000 -mips4 +endif +ifdef CONFIG_CPU_NEVADA +CFLAGS := $(CFLAGS) -mcpu=r8000 -mips3 -mmad +endif +ifdef CONFIG_CPU_R8000 +CFLAGS := $(CFLAGS) -mcpu=r8000 -mips4 +endif +ifdef CONFIG_CPU_R10000 +CFLAGS := $(CFLAGS) -mcpu=r8000 -mips4 +endif + +# +# Board-dependent options and extra files +# +ifdef CONFIG_SGI_IP22 +LIBS += arch/mips64/sgi-ip22/ip22.a arch/mips64/arc/arclib.a +SUBDIRS += arch/mips64/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 +# 16kb aligned or the handling of the current variable will break. +# +LOADADDR += 0x88004000 +endif + +ifdef CONFIG_SGI_IP27 +LIBS += arch/mips64/sgi-ip27/ip27.a arch/mips64/arc/arclib.a +SUBDIRS += arch/mips64/sgi-ip27 arch/mips64/arc +# +# Set LOADADDR to >= 0xc000000000300000 if you want to leave space for +# symmon, 0xc00000000001c000 for production kernels. Note that the value +# must be 16kb aligned or the handling of the current variable will break. +# +#LOADADDR += 0xa80000000001c000 +LOADADDR += 0x8001c000 +endif + +# +# Some machines like the Indy need 32-bit ELF binaries for booting purposes. +# Other need ECOFF, so we build a 32-bit ELF binary for them which we then +# convert to ECOFF using elf2ecoff. +# +ifdef CONFIG_BOOT_ELF32 +CFLAGS += -Wa,-32 +LINKFLAGS += -T arch/mips64/ld.script.elf32 +endif +# +# The 64-bit ELF tools are pretty broken so at this time we generate 64-bit +# ELF files from 32-bit files by conversion. +# +ifdef CONFIG_BOOT_ELF64 +CFLAGS += -Wa,-32 +LINKFLAGS += -T arch/mips64/ld.script.elf32 +#AS += -64 +#LD += -m elf64bmip +#LINKFLAGS += -T arch/mips64/ld.script.elf64 +endif + +LINKFLAGS += -Ttext $(LOADADDR) + +HEAD := arch/mips64/kernel/head.o arch/mips64/kernel/init_task.o + +SUBDIRS := $(addprefix arch/mips64/, tools) $(SUBDIRS) $(addprefix arch/mips64/, kernel mm lib) +CORE_FILES := arch/mips64/kernel/kernel.o arch/mips64/mm/mm.o $(CORE_FILES) +LIBS := arch/mips64/lib/lib.a $(LIBS) + +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot + +ifdef CONFIG_CPU_LITTLE_ENDIAN +64bit-bfd = elf64-littlemips +else +64bit-bfd = elf64-bigmips +endif + +vmlinux.64: vmlinux + $(OBJCOPY) -O $(64bit-bfd) --change-addresses=0xa7ffffff80000000 $< $@ + +zImage: vmlinux + @$(MAKEBOOT) zImage + +compressed: zImage + +zdisk: vmlinux + @$(MAKEBOOT) zdisk + +archclean: + @$(MAKEBOOT) clean + $(MAKE) -C arch/$(ARCH)/kernel clean + $(MAKE) -C arch/$(ARCH)/tools clean + rm -f vmlinux.64 + +archmrproper: + +archdep: + @$(MAKEBOOT) dep diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/Makefile linux/arch/mips64/arc/Makefile --- v2.3.47/linux/arch/mips64/arc/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/Makefile Thu Feb 24 22:53:35 2000 @@ -0,0 +1,14 @@ +# $Id: Makefile,v 1.3 2000/01/17 23:32:46 ralf Exp $ +# +# Makefile for the ARC prom monitor library routines under Linux. +# + +L_TARGET = arclib.a +L_OBJS = console.o init.o printf.o tree.o env.o cmdline.o misc.o time.o \ + file.o identify.o + +ifdef CONFIG_ARC_MEMORY +L_OBJS += memory.o +endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/cmdline.c linux/arch/mips64/arc/cmdline.c --- v2.3.47/linux/arch/mips64/arc/cmdline.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/cmdline.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,67 @@ +/* $Id: cmdline.c,v 1.2 1999/11/19 23:29:05 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * cmdline.c: Kernel command line creation using ARCS argc/argv. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include +#include +#include + +#include +#include + +/* #define DEBUG_CMDLINE */ + +char arcs_cmdline[CL_SIZE]; + +char * __init prom_getcmdline(void) +{ + return &(arcs_cmdline[0]); +} + +static char *ignored[] = { + "ConsoleIn=", + "ConsoleOut=", + "SystemPartition=", + "OSLoader=", + "OSLoadPartition=", + "OSLoadFilename=" +}; +#define NENTS(foo) ((sizeof((foo)) / (sizeof((foo[0]))))) + +void __init prom_init_cmdline(void) +{ + char *cp; + int actr, i; + + actr = 1; /* Always ignore argv[0] */ + + cp = &(arcs_cmdline[0]); + while(actr < prom_argc) { + for(i = 0; i < NENTS(ignored); i++) { + int len = strlen(ignored[i]); + + if(!strncmp(prom_argv(actr), ignored[i], len)) + goto pic_cont; + } + /* Ok, we want it. */ + strcpy(cp, prom_argv(actr)); + cp += strlen(prom_argv(actr)); + *cp++ = ' '; + + pic_cont: + 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 -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/console.c linux/arch/mips64/arc/console.c --- v2.3.47/linux/arch/mips64/arc/console.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/console.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,30 @@ +/* $Id: console.c,v 1.3 1999/11/19 23:29:05 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * ARC console code. + * + * Copyright (C) 1996 David S. Miller (dm@sgi.com) + */ +#include +#include + +void __init prom_putchar(char c) +{ + ULONG cnt; + CHAR it = c; + + ArcWrite(1, &it, 1, &cnt); +} + +char __init prom_getchar(void) +{ + ULONG cnt; + CHAR c; + + ArcRead(0, &c, 1, &cnt); + + return c; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/env.c linux/arch/mips64/arc/env.c --- v2.3.47/linux/arch/mips64/arc/env.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/env.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,28 @@ +/* $Id: env.c,v 1.4 1999/11/19 23:29:05 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * env.c: ARCS environment variable routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include +#include +#include + +#include +#include + +PCHAR __init +ArcGetEnvironmentVariable(CHAR *name) +{ + return (CHAR *) ARC_CALL1(get_evar, name); +} + +LONG __init +ArcSetEnvironmentVariable(PCHAR name, PCHAR value) +{ + return ARC_CALL2(set_evar, name, value); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/file.c linux/arch/mips64/arc/file.c --- v2.3.47/linux/arch/mips64/arc/file.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/file.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,76 @@ +/* $Id: file.c,v 1.3 1999/11/19 23:29:05 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * ARC firmware interface. + * + * Copyright (C) 1994, 1995, 1996, 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include + +#include +#include + +LONG __init +ArcGetDirectoryEntry(ULONG FileID, struct linux_vdirent *Buffer, + ULONG N, ULONG *Count) +{ + return ARC_CALL4(get_vdirent, FileID, Buffer, N, Count); +} + +LONG __init +ArcOpen(CHAR *Path, enum linux_omode OpenMode, ULONG *FileID) +{ + return ARC_CALL3(open, Path, OpenMode, FileID); +} + +LONG __init +ArcClose(ULONG FileID) +{ + return ARC_CALL1(close, FileID); +} + +LONG __init +ArcRead(ULONG FileID, VOID *Buffer, ULONG N, ULONG *Count) +{ + return ARC_CALL4(read, FileID, Buffer, N, Count); +} + +LONG __init +ArcGetReadStatus(ULONG FileID) +{ + return ARC_CALL1(get_rstatus, FileID); +} + +LONG __init +ArcWrite(ULONG FileID, PVOID Buffer, ULONG N, PULONG Count) +{ + return ARC_CALL4(write, FileID, Buffer, N, Count); +} + +LONG __init +ArcSeek(ULONG FileID, struct linux_bigint *Position, enum linux_seekmode SeekMode) +{ + return ARC_CALL3(seek, FileID, Position, SeekMode); +} + +LONG __init +ArcMount(char *name, enum linux_mountops op) +{ + return ARC_CALL2(mount, name, op); +} + +LONG __init +ArcGetFileInformation(ULONG FileID, struct linux_finfo *Information) +{ + return ARC_CALL2(get_finfo, FileID, Information); +} + +LONG __init ArcSetFileInformation(ULONG FileID, ULONG AttributeFlags, + ULONG AttributeMask) +{ + return ARC_CALL3(set_finfo, FileID, AttributeFlags, AttributeMask); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/identify.c linux/arch/mips64/arc/identify.c --- v2.3.47/linux/arch/mips64/arc/identify.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/identify.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,83 @@ +/* $Id: identify.c,v 1.5 2000/01/17 23:32: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. + * + * identify.c: identify machine by looking up system identifier + * + * Copyright (C) 1998 Thomas Bogendoerfer + * + * This code is based on arch/mips/sgi/kernel/system.c, which is + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include +#include +#include +#include +#include + +#include +#include + +struct smatch { + char *name; + 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 } +}; + +int prom_flags; + +static struct smatch * __init +string_to_mach(char *s) +{ + int i; + + for (i = 0; i < sizeof (mach_table); i++) { + if(!strcmp(s, mach_table[i].name)) + return &mach_table[i]; + } + prom_printf("\nYeee, could not determine architecture type <%s>\n", s); + prom_printf("press a key to reboot\n"); + prom_getchar(); + ArcEnterInteractiveMode(); + + return NULL; +} + +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 = 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); + + mips_machgroup = mach->group; + mips_machtype = mach->type; + prom_flags = mach->flags; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/init.c linux/arch/mips64/arc/init.c --- v2.3.47/linux/arch/mips64/arc/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/init.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,62 @@ +/* $Id: init.c,v 1.3 1999/11/19 23:29:05 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * PROM library initialisation code. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include +#include +#include + +#include + +#undef DEBUG_PROM_INIT + +/* Master romvec interface. */ +struct linux_romvec *romvec; +PSYSTEM_PARAMETER_BLOCK sgi_pblock; +int prom_argc; +LONG *_prom_argv, *_prom_envp; +unsigned short prom_vers, prom_rev; + +extern void prom_testtree(void); + +int __init +prom_init(int argc, char **argv, char **envp) +{ + PSYSTEM_PARAMETER_BLOCK pb; + + romvec = ROMVECTOR; + pb = sgi_pblock = PROMBLOCK; + prom_argc = argc; + _prom_argv = (LONG *) argv; + _prom_envp = (LONG *) envp; + + if(pb->magic != 0x53435241) { + prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic); + while(1) + ; + } + + prom_init_cmdline(); + + prom_vers = pb->ver; + prom_rev = pb->rev; + prom_identify_arch(); + printk("PROMLIB: ARC firmware Version %d Revision %d\n", + prom_vers, prom_rev); + prom_meminit(); + +#ifdef DEBUG_PROM_INIT + { + prom_printf("Press a key to reboot\n"); + (void) prom_getchar(); + ArcEnterInteractiveMode(); + } +#endif + return 0; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/memory.c linux/arch/mips64/arc/memory.c --- v2.3.47/linux/arch/mips64/arc/memory.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/memory.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,248 @@ +/* $Id: memory.c,v 1.5 2000/01/27 23:21:57 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 by David S. Miller + * Copyright (C) 1999, 2000 by Ralf Baechle + * Copyright (C) 1999, 2000 by Silicon Graphics, Inc. + * + * PROM library functions for acquiring/using memory descriptors given to us + * from the ARCS firmware. This is only used when CONFIG_ARC_MEMORY is set + * because on some machines like SGI IP27 the ARC memory configuration data + * completly bogus and alternate easier to use mechanisms are available. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#undef DEBUG + +extern char _end; + +struct linux_mdesc * __init +ArcGetMemoryDescriptor(struct linux_mdesc *Current) +{ + return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current); +} + +#ifdef DEBUG /* convenient for debugging */ +static char *arcs_mtypes[8] = { + "Exception Block", + "ARCS Romvec Page", + "Free/Contig RAM", + "Generic Free RAM", + "Bad Memory", + "Standlong Program Pages", + "ARCS Temp Storage Area", + "ARCS Permanent Storage Area" +}; + +static char *arc_mtypes[8] = { + "Exception Block", + "SystemParameterBlock", + "FreeMemory", + "Bad Memory", + "LoadedProgram", + "FirmwareTemporary", + "FirmwarePermanent", + "FreeContigiuous" +}; +#define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc] +#endif + +static struct prom_pmemblock pblocks[PROM_MAX_PMEMBLOCKS]; + +#define MEMTYPE_DONTUSE 0 +#define MEMTYPE_PROM 1 +#define MEMTYPE_FREE 2 + +static inline int memtype_classify_arcs (union linux_memtypes type) +{ + switch (type.arcs) { + case arcs_fcontig: + case arcs_free: + return MEMTYPE_FREE; + case arcs_atmp: + return MEMTYPE_PROM; + case arcs_eblock: + case arcs_rvpage: + case arcs_bmem: + case arcs_prog: + case arcs_aperm: + return MEMTYPE_DONTUSE; + default: + BUG(); + } + while(1); /* Nuke warning. */ +} + +static inline int memtype_classify_arc (union linux_memtypes type) +{ + switch (type.arc) { + case arc_free: + case arc_fcontig: + return MEMTYPE_FREE; + case arc_atmp: + return MEMTYPE_PROM; + case arc_eblock: + case arc_rvpage: + case arc_bmem: + case arc_prog: + case arc_aperm: + return MEMTYPE_DONTUSE; + default: + BUG(); + } + while(1); /* Nuke warning. */ +} + +static int __init prom_memtype_classify (union linux_memtypes type) +{ + if (prom_flags & PROM_FLAG_ARCS) /* SGI is ``different'' ... */ + return memtype_classify_arcs(type); + + return memtype_classify_arc(type); +} + +static inline unsigned long find_max_low_pfn(void) +{ + struct prom_pmemblock *p, *highest; + unsigned long pfn; + + p = pblocks; + highest = 0; + while (p->size != 0) { + if (!highest || p->base > highest->base) + highest = p; + p++; + } + + pfn = (highest->base + highest->size) >> PAGE_SHIFT; +#ifdef DEBUG + prom_printf("find_max_low_pfn: 0x%lx pfns.\n", pfn); +#endif + return pfn; +} + +static inline struct prom_pmemblock *find_largest_memblock(void) +{ + struct prom_pmemblock *p, *largest; + + p = pblocks; + largest = 0; + while (p->size != 0) { + if (!largest || p->size > largest->size) + largest = p; + p++; + } + + return largest; +} + +void __init prom_meminit(void) +{ + struct prom_pmemblock *largest; + unsigned long bootmap_size; + struct linux_mdesc *p; + int totram; + int i = 0; + +#ifdef DEBUG + prom_printf("ARCS MEMORY DESCRIPTOR dump:\n"); + p = ArcGetMemoryDescriptor(PROM_NULL_MDESC); + while(p) { + prom_printf("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n", + i, p, p->base, p->pages, mtypes(p->type)); + p = ArcGetMemoryDescriptor(p); + i++; + } +#endif + + totram = 0; + i = 0; + p = PROM_NULL_MDESC; + while ((p = ArcGetMemoryDescriptor(p))) { + pblocks[i].type = prom_memtype_classify(p->type); + pblocks[i].base = p->base << PAGE_SHIFT; + pblocks[i].size = p->pages << PAGE_SHIFT; + + switch (pblocks[i].type) { + case MEMTYPE_FREE: + totram += pblocks[i].size; +#ifdef DEBUG + prom_printf("free_chunk[%d]: base=%08lx size=%x\n", + i, pblocks[i].base, + pblocks[i].size); +#endif + i++; + break; + case MEMTYPE_PROM: +#ifdef DEBUG + prom_printf("prom_chunk[%d]: base=%08lx size=%x\n", + i, pblocks[i].base, + pblocks[i].size); +#endif + i++; + break; + default: + break; + } + } + pblocks[i].size = 0; + + max_low_pfn = find_max_low_pfn(); + largest = find_largest_memblock(); + bootmap_size = init_bootmem(largest->base >> PAGE_SHIFT, max_low_pfn); + + for (i = 0; pblocks[i].size; i++) + if (pblocks[i].type == MEMTYPE_FREE) + free_bootmem(pblocks[i].base, pblocks[i].size); + + /* This test is simpleminded. It will fail if the bootmem bitmap + falls into multiple adjacent ARC memory areas. */ + if (bootmap_size > largest->size) { + prom_printf("CRITIAL: overwriting PROM data.\n"); + BUG(); + } + reserve_bootmem(largest->base, bootmap_size); + + printk("PROMLIB: Total free ram %dK / %dMB.\n", + totram >> 10, totram >> 20); +} + +void __init +prom_free_prom_memory (void) +{ + struct prom_pmemblock *p; + unsigned long freed = 0; + unsigned long addr, end; + + for (p = pblocks; p->size != 0; p++) { + if (p->type != MEMTYPE_PROM) + continue; + + addr = PAGE_OFFSET + (unsigned long) (long) p->base; + end = addr + (unsigned long) (long) p->size; + while (addr < end) { + ClearPageReserved(mem_map + MAP_NR(addr)); + set_page_count(mem_map + MAP_NR(addr), 1); + free_page(addr); + addr += PAGE_SIZE; + freed += PAGE_SIZE; + } + } + printk("Freeing prom memory: %ldkb freed\n", freed >> 10); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/misc.c linux/arch/mips64/arc/misc.c --- v2.3.47/linux/arch/mips64/arc/misc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/misc.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,105 @@ +/* $Id: misc.c,v 1.4 2000/01/17 23:32: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. + * + * 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 + +extern unsigned long mips_cputype; +extern void *sgiwd93_host; +extern void reset_wd33c93(void *instance); + +VOID +ArcHalt(VOID) +{ + bc_disable(); + cli(); +#if CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + ARC_CALL0(halt); +never: goto never; +} + +VOID +ArcPowerDown(VOID) +{ + bc_disable(); + cli(); +#if CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + ARC_CALL0(pdown); +never: goto never; +} + +/* XXX is this a soft reset basically? XXX */ +VOID +ArcRestart(VOID) +{ + bc_disable(); + cli(); +#if CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + ARC_CALL0(restart); +never: goto never; +} + +VOID +ArcReboot(VOID) +{ + bc_disable(); + cli(); +#if CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + ARC_CALL0(reboot); +never: goto never; +} + +VOID +ArcEnterInteractiveMode(VOID) +{ + bc_disable(); + cli(); +#if CONFIG_SCSI_SGIWD93 + reset_wd33c93(sgiwd93_host); +#endif + ARC_CALL0(imode); +never: goto never; +} + +LONG +ArcSaveConfiguration(VOID) +{ + return ARC_CALL0(cfg_save); +} + +struct linux_sysid * +ArcGetSystemId(VOID) +{ + return (struct linux_sysid *) ARC_CALL0(get_sysid); +} + +VOID __init +ArcFlushAllCaches(VOID) +{ + ARC_CALL0(cache_flush); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/printf.c linux/arch/mips64/arc/printf.c --- v2.3.47/linux/arch/mips64/arc/printf.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/printf.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,37 @@ +/* $Id: printf.c,v 1.2 1999/11/19 23:29:05 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Putting things on the screen using SGI arcs PROM facilities. + * + * Copyright (C) 1996 David S. Miller (dm@sgi.com) + */ +#include +#include + +#include + +static char ppbuf[1024]; + +void __init prom_printf(char *fmt, ...) +{ + va_list args; + char ch, *bptr; + int i; + + va_start(args, fmt); + i = vsprintf(ppbuf, fmt, args); + + bptr = ppbuf; + + while((ch = *(bptr++)) != 0) { + if(ch == '\n') + prom_putchar('\r'); + + prom_putchar(ch); + } + va_end(args); + return; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/salone.c linux/arch/mips64/arc/salone.c --- v2.3.47/linux/arch/mips64/arc/salone.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/salone.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,28 @@ +/* $Id: salone.c,v 1.3 1999/11/19 23:29:05 ralf Exp $ + * + * Routines to load into memory and execute stand-along program images using + * ARCS PROM firmware. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include +#include + +LONG __init +ArcLoad(CHAR *Path, ULONG TopAddr, ULONG *ExecAddr, ULONG *LowAddr) +{ + return ARC_CALL4(load, Path, TopAddr, ExecAddr, LowAddr); +} + +LONG __init +ArcInvoke(ULONG ExecAddr, ULONG StackAddr, ULONG Argc, CHAR *Argv[], + CHAR *Envp[]) +{ + return ARC_CALL5(invoke, ExecAddr, StackAddr, Argc, Argv, Envp); +} + +LONG __init +ArcExecute(CHAR *Path, LONG Argc, CHAR *Argv[], CHAR *Envp[]) +{ + return ARC_CALL4(exec, Path, Argc, Argv, Envp); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/time.c linux/arch/mips64/arc/time.c --- v2.3.47/linux/arch/mips64/arc/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/time.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,26 @@ +/* $Id: time.c,v 1.3 1999/11/19 23:29:05 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Extracting time information from ARCS prom. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#include + +#include +#include + +struct linux_tinfo * __init +ArcGetTime(VOID) +{ + return (struct linux_tinfo *) ARC_CALL0(get_tinfo); +} + +ULONG __init +ArcGetRelativeTime(VOID) +{ + return ARC_CALL0(get_rtime); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/arc/tree.c linux/arch/mips64/arc/tree.c --- v2.3.47/linux/arch/mips64/arc/tree.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/arc/tree.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,130 @@ +/* $Id: tree.c,v 1.4 1999/11/19 23:29:05 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * PROM component device tree code. + * + * 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 + +#undef DEBUG_PROM_TREE + +pcomponent * __init +ArcGetPeer(pcomponent *Current) +{ + if (Current == PROM_NULL_COMPONENT) + return PROM_NULL_COMPONENT; + + return (pcomponent *) ARC_CALL1(next_component, Current); +} + +pcomponent * __init +ArcGetChild(pcomponent *Current) +{ + return (pcomponent *) ARC_CALL1(child_component, Current); +} + +pcomponent * __init +ArcGetParent(pcomponent *Current) +{ + if (Current == PROM_NULL_COMPONENT) + return PROM_NULL_COMPONENT; + + return (pcomponent *) ARC_CALL1(parent_component, Current); +} + +LONG __init +ArcGetConfigurationData(VOID *Buffer, pcomponent *Current) +{ + return ARC_CALL2(component_data, Buffer, Current); +} + +pcomponent * __init +ArcAddChild(pcomponent *Current, pcomponent *Template, VOID *ConfigurationData) +{ + return (pcomponent *) + ARC_CALL3(child_add, Current, Template, ConfigurationData); +} + +LONG __init +ArcDeleteComponent(pcomponent *ComponentToDelete) +{ + return ARC_CALL1(comp_del, ComponentToDelete); +} + +pcomponent * __init +ArcGetComponent(CHAR *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" +}; + +static char *iflags[] = { + "bogus", "read only", "removable", "console in", "console out", + "input", "output" +}; + +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], + iflags[p->iflags], p->vers, p->rev); + prom_printf("key<%08lx>\n\tamask<%08lx>cdsize<%d>ilen<%d>iname<%s>\n", + p->key, p->amask, (int)p->cdsize, (int)p->ilen, p->iname); +} + +static void __init +traverse(pcomponent *p, int op) +{ + dump_component(p); + if(ArcGetChild(p)) + traverse(ArcGetChild(p), 1); + if(ArcGetPeer(p) && op) + traverse(ArcGetPeer(p), 1); +} + +void __init +prom_testtree(void) +{ + pcomponent *p; + + p = ArcGetChild(PROM_NULL_COMPONENT); + dump_component(p); + p = ArcGetChild(p); + while(p) { + dump_component(p); + p = ArcGetPeer(p); + } + prom_printf("press a key\n"); + prom_getchar(); +} + +#endif /* DEBUG_PROM_TREE */ diff -u --recursive --new-file v2.3.47/linux/arch/mips64/boot/Makefile linux/arch/mips64/boot/Makefile --- v2.3.47/linux/arch/mips64/boot/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/boot/Makefile Thu Feb 24 22:53:35 2000 @@ -0,0 +1,43 @@ +# $Id: Makefile,v 1.2 1999/12/04 03:59:00 ralf Exp $ +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995, 1998, 1999 by Ralf Baechle +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +# +# Some DECstations need all possible sections of an ECOFF executable +# +ifdef CONFIG_DECSTATION + E2EFLAGS = -a +else + E2EFLAGS = +endif + +all: vmlinux.ecoff addinitrd + +vmlinux.ecoff: $(CONFIGURE) elf2ecoff $(TOPDIR)/vmlinux + ./elf2ecoff $(TOPDIR)/vmlinux vmlinux.ecoff $(E2EFLAGS) + +elf2ecoff: elf2ecoff.c + $(HOSTCC) -o $@ $^ + +addinitrd: addinitrd.c + $(HOSTCC) -o $@ $^ + +# Don't build dependencies, this may die if $(CC) isn't gcc +dep: + +clean: + rm -f vmlinux.ecoff + +dummy: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/arch/mips64/config.in linux/arch/mips64/config.in --- v2.3.47/linux/arch/mips64/config.in Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/config.in Thu Feb 24 22:53:35 2000 @@ -0,0 +1,224 @@ +# $Id: config.in,v 1.14 2000/02/18 11:06:20 ulfc Exp $ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +mainmenu_name "Linux Kernel Configuration" + +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + +mainmenu_option next_comment +comment 'Machine selection' +bool 'Support for SGI IP22' CONFIG_SGI_IP22 +bool 'Support for SGI IP27' CONFIG_SGI_IP27 +if [ "$CONFIG_SGI_IP27" = "y" ]; then + bool ' IP27 N-Mode' CONFIG_SGI_SN0_N_MODE + bool ' Discontiguous Memory Support' CONFIG_DISCONTIGMEM + #bool ' IP27 XXL' CONFIG_SGI_SN0_XXL +fi +endmenu + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Symmetric Multi-Processing support' CONFIG_SMP +fi + +# +# Select some configuration options automatically based on user selections +# +unset CONFIG_BOOT_ELF32 +unset CONFIG_BOOT_ELF64 +unset CONFIG_ARC32 +unset CONFIG_ARC64 +unset CONFIG_BOARD_SCACHE +unset CONFIG_COHERENT_IO +unset CONFIG_BINFMT_ELF32 +unset CONFIG_PCI + +if [ "$CONFIG_SGI_IP22" = "y" ]; then + define_bool CONFIG_BOOT_ELF32 y + define_bool CONFIG_ARC32 y + define_bool CONFIG_BOARD_SCACHE y + define_bool CONFIG_ARC_MEMORY y +fi + +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_PCI y + define_bool CONFIG_QL_ISP_A64 y +fi + +mainmenu_option next_comment +comment 'CPU selection' + +choice 'CPU type' \ + "R4300 CONFIG_CPU_R4300 \ + R4x00 CONFIG_CPU_R4X00 \ + R5000 CONFIG_CPU_R5000 \ + R56x0 CONFIG_CPU_NEVADA \ + R8000 CONFIG_CPU_R8000 \ + R10000 CONFIG_CPU_R10000" R4x00 +endmenu + +mainmenu_option next_comment +comment 'General setup' + +if [ "$CONFIG_CPU_R10000" = "y" ]; then + bool 'Support for large 64-bit configurations' CONFIG_MIPS_INSANE_LARGE +fi +bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN + +bool 'Networking support' CONFIG_NET + +source drivers/pci/Config.in +source drivers/pcmcia/Config.in + +bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT +bool 'Sysctl support' CONFIG_SYSCTL +tristate 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF +bool 'Kernel support for Linux/MIPS 32-bit binary compatibility' CONFIG_MIPS32_COMPAT +if [ "$CONFIG_MIPS32_COMPAT" = "y" ]; then + define_bool CONFIG_BINFMT_ELF32 y +fi +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC + +endmenu + +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool 'Kernel module loader' CONFIG_KMOD +fi + +source drivers/pci/Config.in + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB +fi + +endmenu + +source drivers/block/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +source drivers/telephony/Config.in + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + source drivers/scsi/Config.in +fi +endmenu + +source drivers/i2o/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + if [ "$CONFIG_SGI_IP22" = "y" ]; then + bool 'SGI Seeq ethernet controller support' CONFIG_SGISEEQ + fi + if [ "$CONFIG_DECSTATION" = "y" ]; then + bool 'DEC LANCE ethernet controller support' CONFIG_DECLANCE + fi + if [ "$CONFIG_BAGET_MIPS" = "y" ]; then + tristate 'Baget AMD LANCE support' CONFIG_BAGETLANCE + tristate 'Baget Backplane Shared Memory support' CONFIG_BAGETBSM + fi + if [ "$CONFIG_ATM" = "y" ]; then + source drivers/atm/Config.in + fi + fi + endmenu +fi + +source net/ax25/Config.in + +source net/irda/Config.in + +mainmenu_option next_comment +comment 'ISDN subsystem' + +if [ "$CONFIG_NET" != "n" ]; then + tristate 'ISDN support' CONFIG_ISDN + if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in + fi +fi +endmenu + +mainmenu_option next_comment +comment 'Old CD-ROM drivers (not SCSI, not IDE)' + +bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI +if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then + source drivers/cdrom/Config.in +fi +endmenu + +source drivers/char/Config.in + +source drivers/usb/Config.in + +# drivers/misc has currently only i386 specific devices. +#source drivers/misc/Config.in + +source fs/Config.in + +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + if [ "$CONFIG_SGI_IP22" = "y" ]; then + tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE + if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then + define_bool CONFIG_DUMMY_CONSOLE y + fi + fi + endmenu +fi + +if [ "$CONFIG_PROC_FS" = "y" ]; then + define_bool CONFIG_KCORE_ELF y +fi + +mainmenu_option next_comment +comment 'Sound' + +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu + +if [ "$CONFIG_SGI_IP22" = "y" ]; then + source drivers/sgi/Config.in +fi + +mainmenu_option next_comment +comment 'Kernel hacking' + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE +if [ "$CONFIG_MODULES" = "y" ]; then + bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE +fi +bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +endmenu diff -u --recursive --new-file v2.3.47/linux/arch/mips64/defconfig linux/arch/mips64/defconfig --- v2.3.47/linux/arch/mips64/defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/defconfig Thu Feb 24 22:53:35 2000 @@ -0,0 +1,395 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Machine selection +# +# CONFIG_SGI_IP22 is not set +CONFIG_SGI_IP27=y +# CONFIG_SGI_SN0_N_MODE is not set +# CONFIG_DISCONTIGMEM is not set +CONFIG_BOOT_ELF64=y +CONFIG_ARC64=y +CONFIG_COHERENT_IO=y +CONFIG_PCI=y +CONFIG_QL_ISP_A64=y + +# +# 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=y + +# +# General setup +# +# CONFIG_MIPS_INSANE_LARGE is not set +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_NET=y +CONFIG_PCI_NAMES=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA 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 + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_CPQ_DA is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD 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=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ 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_ST_EXTRA_DEVS=2 +# 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_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_IPS 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_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_SYM53C416 is not set +# CONFIG_SCSI_SIM710 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=y +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR 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_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_SGI_IOC3_ETH=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_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_EISA is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC 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 driver support +# +# 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=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV 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_DRM is not set +# CONFIG_DRM_TDFX is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_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_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_CRAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_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_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_SYSV_FS_WRITE 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_NFS_FS=y +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 + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_SGI_PARTITION=y +# CONFIG_NLS is not set +CONFIG_KCORE_ELF=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +CONFIG_MAGIC_SYSRQ=y diff -u --recursive --new-file v2.3.47/linux/arch/mips64/defconfig-ip22 linux/arch/mips64/defconfig-ip22 --- v2.3.47/linux/arch/mips64/defconfig-ip22 Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/defconfig-ip22 Thu Feb 24 22:53:35 2000 @@ -0,0 +1,321 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Machine selection +# +CONFIG_SGI_IP22=y +# CONFIG_SGI_IP27 is not set +CONFIG_BOOT_ELF32=y +CONFIG_ARC32=y +CONFIG_BOARD_SCACHE=y +CONFIG_ARC_MEMORY=y + +# +# 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 + +# +# General setup +# +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_NET=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA 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 is not set +# CONFIG_BINFMT_MISC is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_ONLY is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD 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=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ 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_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +# CONFIG_NET_ETHERNET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC 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 driver support +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_SGISEEQ=y + +# +# 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 is not set +# CONFIG_UNIX98_PTYS is not set +# 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_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV 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_DRM is not set +# CONFIG_DRM_TDFX is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_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_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_CRAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_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_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS 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_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_SGI_PARTITION=y +# CONFIG_NLS is not set + +# +# Console drivers +# +CONFIG_SGI_NEWPORT_CONSOLE=y +CONFIG_KCORE_ELF=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# SGI devices +# +# CONFIG_SGI_SERIAL is not set +CONFIG_SGI_DS1286=y + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +# CONFIG_MAGIC_SYSRQ is not set diff -u --recursive --new-file v2.3.47/linux/arch/mips64/defconfig-ip27 linux/arch/mips64/defconfig-ip27 --- v2.3.47/linux/arch/mips64/defconfig-ip27 Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/defconfig-ip27 Thu Feb 24 22:53:35 2000 @@ -0,0 +1,395 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set + +# +# Machine selection +# +# CONFIG_SGI_IP22 is not set +CONFIG_SGI_IP27=y +# CONFIG_SGI_SN0_N_MODE is not set +# CONFIG_DISCONTIGMEM is not set +CONFIG_BOOT_ELF64=y +CONFIG_ARC64=y +CONFIG_COHERENT_IO=y +CONFIG_PCI=y +CONFIG_QL_ISP_A64=y + +# +# 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=y + +# +# General setup +# +# CONFIG_MIPS_INSANE_LARGE is not set +# CONFIG_CPU_LITTLE_ENDIAN is not set +CONFIG_NET=y +CONFIG_PCI_NAMES=y + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA 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 + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_IDE is not set + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_ONLY is not set +# CONFIG_BLK_CPQ_DA is not set + +# +# Additional Block Devices +# +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD 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=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_SYN_COOKIES is not set + +# +# (it is safe to leave these untouched) +# +CONFIG_SKB_LARGE=y + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set +# CONFIG_PHONE_IXJ 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_ST_EXTRA_DEVS=2 +# 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_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_IPS 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_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_SYM53C416 is not set +# CONFIG_SCSI_SIM710 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=y +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_ULTRASTOR 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_EQUALIZER is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_SGI_IOC3_ETH=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_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_EISA is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC 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 driver support +# +# 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=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_PRINTER is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV 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_DRM is not set +# CONFIG_DRM_TDFX is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_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_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_CRAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_MINIX_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_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_SYSV_FS_WRITE 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_NFS_FS=y +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 + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_SGI_PARTITION=y +# CONFIG_NLS is not set +CONFIG_KCORE_ELF=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Kernel hacking +# +CONFIG_CROSSCOMPILE=y +# CONFIG_REMOTE_DEBUG is not set +CONFIG_MAGIC_SYSRQ=y diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/Makefile linux/arch/mips64/kernel/Makefile --- v2.3.47/linux/arch/mips64/kernel/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/Makefile Thu Feb 24 22:53:35 2000 @@ -0,0 +1,30 @@ +# +# Makefile for the Linux/MIPS 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.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: kernel.o head.o init_task.o + +O_TARGET := kernel.o +O_OBJS := branch.o entry.o proc.o process.o ptrace.o r4k_cache.o r4k_fpu.o \ + r4k_genex.o r4k_switch.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 +OX_OBJS := mips64_ksyms.o + +ifdef CONFIG_MIPS32_COMPAT +O_OBJS += linux32.o scall_o32.o signal32.o +endif + +ifdef CONFIG_BINFMT_ELF32 +O_OBJS += binfmt_elf32.o +endif + +clean: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/binfmt_elf32.c linux/arch/mips64/kernel/binfmt_elf32.c --- v2.3.47/linux/arch/mips64/kernel/binfmt_elf32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/binfmt_elf32.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,100 @@ +/* $Id: binfmt_elf32.c,v 1.2 2000/01/17 23:32:46 ralf Exp $ + * + * Support for 32-bit Linux/MIPS ELF binaries. + * + * Copyright (C) 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + * + * Heavily inspired by the 32-bit Sparc compat code which is + * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com) + * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#define ELF_ARCH EM_MIPS +#define ELF_CLASS ELFCLASS32 +#ifdef __MIPSEB__ +#define ELF_DATA ELFDATA2MSB; +#else /* __MIPSEL__ */ +#define ELF_DATA ELFDATA2LSB; +#endif + +/* ELF register definitions */ +#define ELF_NGREG 45 +#define ELF_NFPREG 33 + +typedef unsigned int elf_greg_t; +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef double elf_fpreg_t; +typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +#define elf_check_arch(x) ((x) == EM_MIPS || (x) == EM_MIPS_RS4_BE) + +#define TASK32_SIZE 0x80000000UL +#undef ELF_ET_DYN_BASE +#define ELF_ET_DYN_BASE (2 * TASK32_SIZE / 3) + +#include +#include +#include +#include + +struct timeval32 +{ + unsigned 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; /* GP 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 */ + u16 pr_uid; + u16 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 */ +}; + +#define elf_addr_t u32 +#define elf_caddr_t u32 +#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 + +MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux/MIPS binaries"); +MODULE_AUTHOR("Ralf Baechle (ralf@oss.sgi.com)"); + +#undef MODULE_DESCRIPTION +#undef MODULE_AUTHOR + +#include "../../../fs/binfmt_elf.c" diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/branch.c linux/arch/mips64/kernel/branch.c --- v2.3.47/linux/arch/mips64/kernel/branch.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/branch.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,194 @@ +/* $Id: branch.c,v 1.1 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Branch and jump emulation. + * + * Copyright (C) 1996, 1997 by Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include + +/* + * Compute the return address and do emulate branch simulation, if required. + */ +int __compute_return_epc(struct pt_regs *regs) +{ + unsigned int *addr, bit, fcr31; + long epc; + union mips_instruction insn; + + epc = regs->cp0_epc; + if (epc & 3) { + printk("%s: unaligned epc - sending SIGBUS.\n", current->comm); + force_sig(SIGBUS, current); + return -EFAULT; + } + + /* + * Read the instruction + */ + addr = (unsigned int *) epc; + if (__get_user(insn.word, addr)) { + force_sig(SIGSEGV, current); + return -EFAULT; + } + + regs->regs[0] = 0; + switch (insn.i_format.opcode) { + /* + * jr and jalr are in r_format format. + */ + case spec_op: + switch (insn.r_format.func) { + case jalr_op: + regs->regs[insn.r_format.rd] = epc + 8; + /* Fall through */ + case jr_op: + regs->cp0_epc = regs->regs[insn.r_format.rs]; + break; + } + break; + + /* + * This group contains: + * bltz_op, bgez_op, bltzl_op, bgezl_op, + * bltzal_op, bgezal_op, bltzall_op, bgezall_op. + */ + case bcond_op: + switch (insn.i_format.rt) { + case bltz_op: + case bltzl_op: + if (regs->regs[insn.i_format.rs] < 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case bgez_op: + case bgezl_op: + if (regs->regs[insn.i_format.rs] >= 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case bltzal_op: + case bltzall_op: + regs->regs[31] = epc + 8; + if (regs->regs[insn.i_format.rs] < 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case bgezal_op: + case bgezall_op: + regs->regs[31] = epc + 8; + if (regs->regs[insn.i_format.rs] >= 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + } + break; + + /* + * These are unconditional and in j_format. + */ + case jal_op: + regs->regs[31] = regs->cp0_epc + 8; + case j_op: + epc += 4; + epc >>= 28; + epc <<= 28; + epc |= (insn.j_format.target << 2); + regs->cp0_epc = epc; + break; + + /* + * These are conditional and in i_format. + */ + case beq_op: + case beql_op: + if (regs->regs[insn.i_format.rs] == + regs->regs[insn.i_format.rt]) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case bne_op: + case bnel_op: + if (regs->regs[insn.i_format.rs] != + regs->regs[insn.i_format.rt]) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case blez_op: /* not really i_format */ + case blezl_op: + /* rt field assumed to be zero */ + if (regs->regs[insn.i_format.rs] <= 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case bgtz_op: + case bgtzl_op: + /* rt field assumed to be zero */ + if (regs->regs[insn.i_format.rs] > 0) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + /* + * And now the FPA/cp1 branch instructions. + */ + case cop1_op: + asm ("cfc1\t%0,$31":"=r" (fcr31)); + bit = (insn.i_format.rt >> 2); + bit += (bit != 0); + bit += 23; + switch (insn.i_format.rt) { + case 0: /* bc1f */ + case 2: /* bc1fl */ + if (~fcr31 & (1 << bit)) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + + case 1: /* bc1t */ + case 3: /* bc1tl */ + if (fcr31 & (1 << bit)) + epc = epc + 4 + (insn.i_format.simmediate << 2); + else + epc += 8; + regs->cp0_epc = epc; + break; + } + break; + } + + return 0; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/entry.S linux/arch/mips64/kernel/entry.S --- v2.3.47/linux/arch/mips64/kernel/entry.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/entry.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,78 @@ +/* $Id: entry.S,v 1.5 2000/02/23 00:41:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Low level exception handling + * + * Copyright (C) 1994 - 2000 by Ralf Baechle + * Copyright (C) 1999, 2000 Silicon Graphics + */ +#include +#include +#include +#include + + .text + .set noreorder + .align 4 +FEXPORT(ret_from_fork) + jal schedule_tail + move a0, v0 # prev + j ret_from_sys_call + nop +FEXPORT(handle_softirq) + jal do_softirq + nop + b 9f + nop + +reschedule: jal schedule + nop + +FEXPORT(ret_from_sys_call) +FEXPORT(ret_from_irq) +#ifdef __SMP__ +#error Barffff... +#else + la t1, softirq_state +#endif + lw t0, 0 (t1) + lw t1, 4 (t1) # unused delay slot + and t0, t1 + bnez t0, handle_softirq +9: ld t0, PT_STATUS(sp) # returning to kernel mode? + + andi t1, t0, 0x10 + beqz t1, return # -> yes + ld t1, TASK_NEED_RESCHED($28) + bnez t1, reschedule + lw v0, TASK_SIGPENDING($28) + move a0, zero + beqz v0, return + nop + jal do_signal + move a1, sp + +FEXPORT(return) .set noat + RESTORE_ALL + eret + .set at + +/* + * Common spurious interrupt handler. + */ + .text + .align 5 +LEAF(spurious_interrupt) + /* + * 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 + j ret_from_irq + sw t0,%lo(spurious_count)(t1) + END(spurious_interrupt) diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/head.S linux/arch/mips64/kernel/head.S --- v2.3.47/linux/arch/mips64/kernel/head.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/head.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,85 @@ +/* $Id: head.S,v 1.4 2000/01/25 01:35:05 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Head.S contains the MIPS exception handler and startup code. + * + * Copyright (C) 1994, 1995 Waldorf Electronics + * Written by Ralf Baechle and Andreas Busse + * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#define __ASSEMBLY__ +#include +#include +#include +#include +#include +#include +#include + + .text + +EXPORT(stext) # used for profiling +EXPORT(_stext) + + __INIT + +NESTED(kernel_entry, 16, sp) # kernel entry point + +#ifdef CONFIG_ARC64 + /* We get launched at a XKPHYS address but the kernel is linked to + run at a KSEG0 address, so jump there. */ + la t0, 1f + jr t0 +1: +#endif + + ori sp, 0xf # align stack on 16 byte. + xori sp, 0xf + + /* Note that all firmware passed argument registers still + have their values. */ + jal prom_init # initialize firmware + + CLI # disable interrupts + + mfc0 t0, CP0_STATUS + li t1, ~(ST0_CU1|ST0_CU2|ST0_CU3) + and t0, t1 + or t0, (ST0_CU0|ST0_KX|ST0_SX) + mtc0 t0, CP0_STATUS + + 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 + + jal start_kernel +1: b 1b # just in case ... + END(kernel_entry) + + __FINIT + + .comm kernelsp, 8, 8 # current stackpointer + .comm current_pgd, 8, 8 # current page tables + +#define PAGE_SIZE 0x1000 + + .macro page name, order=0 + .globl \name + .org . + (PAGE_SIZE << \order) +\name: .size \name, (PAGE_SIZE << \order) + .type \name, @object + .endm + + .align 12 + .data + + page swapper_pg_dir, 1 + page invalid_pte_table, 1 + page invalid_pmd_table, 1 + page empty_bad_page + page empty_bad_page_table diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/init_task.c linux/arch/mips64/kernel/init_task.c --- v2.3.47/linux/arch/mips64/kernel/init_task.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/init_task.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,25 @@ +#include +#include + +#include +#include + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM(init_mm); + +/* + * Initial task structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by making sure + * the linker maps this in the .text segment right after head.S, + * and making head.S ensure the proper alignment. + * + * The things we do for performance.. + */ +union task_union init_task_union + __attribute__((__section__(".data.init_task"))) = + { INIT_TASK(init_task_union.task) }; diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/linux32.c linux/arch/mips64/kernel/linux32.c --- v2.3.47/linux/arch/mips64/kernel/linux32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/linux32.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,10 @@ +int sys32_newstat(void) {return 0;} +int sys32_newlstat(void) {return 0;} +int sys32_newfstat(void) {return 0;} +int sys_mmap2(void) {return 0;} +int sys_truncate64(void) {return 0;} +int sys_ftruncate64(void) {return 0;} +int sys_stat64(void) {return 0;} +int sys_lstat64(void) {return 0;} +int sys_fstat64(void) {return 0;} + diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/mips64_ksyms.c linux/arch/mips64/kernel/mips64_ksyms.c --- v2.3.47/linux/arch/mips64/kernel/mips64_ksyms.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/mips64_ksyms.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,115 @@ +/* $Id: mips64_ksyms.c,v 1.8 2000/02/24 00:12:41 ralf Exp $ + * + * Export MIPS64-specific functions needed for loadable modules. + * + * 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, 1999 by Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern void *__bzero(void *__s, size_t __count); +extern long __strncpy_from_user_nocheck_asm(char *__to, + const char *__from, long __len); +extern long __strncpy_from_user_asm(char *__to, const char *__from, + long __len); +extern long __strlen_user_nocheck_asm(const char *s); +extern long __strlen_user_asm(const char *s); +extern long __strnlen_user_nocheck_asm(const char *s); +extern long __strnlen_user_asm(const char *s); + +EXPORT_SYMBOL(EISA_bus); + +/* + * String functions + */ +EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(strcat); +EXPORT_SYMBOL_NOVERS(strchr); +EXPORT_SYMBOL_NOVERS(strlen); +EXPORT_SYMBOL_NOVERS(strncat); +EXPORT_SYMBOL_NOVERS(strnlen); +EXPORT_SYMBOL_NOVERS(strrchr); +EXPORT_SYMBOL_NOVERS(strtok); +EXPORT_SYMBOL_NOVERS(strpbrk); + +EXPORT_SYMBOL(_clear_page); +EXPORT_SYMBOL(local_bh_count); +EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(kernel_thread); + +/* + * Userspace access stuff. + */ +EXPORT_SYMBOL_NOVERS(__copy_user); +EXPORT_SYMBOL_NOVERS(__bzero); +EXPORT_SYMBOL_NOVERS(__strncpy_from_user_nocheck_asm); +EXPORT_SYMBOL_NOVERS(__strncpy_from_user_asm); +EXPORT_SYMBOL_NOVERS(__strlen_user_nocheck_asm); +EXPORT_SYMBOL_NOVERS(__strlen_user_asm); +EXPORT_SYMBOL_NOVERS(__strnlen_user_nocheck_asm); +EXPORT_SYMBOL_NOVERS(__strnlen_user_asm); + + +/* Networking helper routines. */ +EXPORT_SYMBOL(csum_partial_copy); + +/* + * Functions to control caches. + */ +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); + +/* + * Base address of ports for Intel style I/O. + */ +EXPORT_SYMBOL(mips_io_port_base); + +/* + * Kernel hacking ... + */ +#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_MIPS_FPE_MODULE +EXPORT_SYMBOL(__compute_return_epc); +EXPORT_SYMBOL(register_fpe); +EXPORT_SYMBOL(unregister_fpe); +#endif + +#ifdef CONFIG_VT +EXPORT_SYMBOL(screen_info); +#endif + +EXPORT_SYMBOL(get_wchan); diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/proc.c linux/arch/mips64/kernel/proc.c --- v2.3.47/linux/arch/mips64/kernel/proc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/proc.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,71 @@ +/* $Id: proc.c,v 1.1 1999/09/28 22:25:51 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1999 Ralf Baechle + * + * XXX Rewrite this mess. + */ +#include +#include +#include +#include +#include +#include +#include + +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) +{ + 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_sec + 2500) / 500000, + ((loops_per_sec + 2500) / 5000) % 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"); +#endif + len += sprintf(buffer + len, "unaligned accesses\t: %lu\n", + unaligned_instructions); + len += sprintf(buffer + len, "wait instruction\t: %s\n", + wait_available ? "yes" : "no"); + len += sprintf(buffer + len, "microsecond timers\t: %s\n", + cyclecounter_available ? "yes" : "no"); + len += sprintf(buffer + len, "extra interrupt vector\t: %s\n", + dedicated_iv_available ? "yes" : "no"); + len += sprintf(buffer + len, "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); + + return len; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/process.c linux/arch/mips64/kernel/process.c --- v2.3.47/linux/arch/mips64/kernel/process.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/process.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,213 @@ +/* $Id: process.c,v 1.5 2000/01/29 01:41:59 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994 - 1999 by Ralf Baechle and others. + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +asmlinkage int cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + current->priority = 0; + current->counter = -100; + while (1) { + while (!current->need_resched) + if (wait_available) + __asm__("wait"); + schedule(); + check_pgt_cache(); + } +} + +struct task_struct *last_task_used_math = NULL; + +asmlinkage void ret_from_fork(void); + +void exit_thread(void) +{ + /* Forget lazy fpu state */ + if (last_task_used_math == current) { + set_cp0_status(ST0_CU1, ST0_CU1); + __asm__ __volatile__("cfc1\t$0,$31"); + last_task_used_math = NULL; + } +} + +void flush_thread(void) +{ + /* Forget lazy fpu state */ + if (last_task_used_math == current) { + set_cp0_status(ST0_CU1, ST0_CU1); + __asm__ __volatile__("cfc1\t$0,$31"); + last_task_used_math = NULL; + } +} + +int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + long childksp; + + childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32; + + if (last_task_used_math == current) { + set_cp0_status(ST0_CU1, ST0_CU1); + save_fp(p); + } + /* set up new TSS. */ + childregs = (struct pt_regs *) childksp - 1; + *childregs = *regs; + childregs->regs[7] = 0; /* Clear error flag */ + if (current->personality == PER_LINUX) { + childregs->regs[2] = 0; /* Child gets zero as return value */ + regs->regs[2] = p->pid; + } else { + /* Under IRIX things are a little different. */ + childregs->regs[2] = 0; + childregs->regs[3] = 1; + regs->regs[2] = p->pid; + regs->regs[3] = 0; + } + if (childregs->cp0_status & ST0_CU0) { + childregs->regs[28] = (unsigned long) p; + childregs->regs[29] = childksp; + p->thread.current_ds = KERNEL_DS; + } else { + childregs->regs[29] = usp; + p->thread.current_ds = USER_DS; + } + p->thread.reg29 = (unsigned long) childregs; + p->thread.reg31 = (unsigned long) ret_from_fork; + + /* + * New tasks loose permission to use the fpu. This accelerates context + * switching for most programs since they don't use the fpu. + */ + p->thread.cp0_status = read_32bit_cp0_register(CP0_STATUS) & + ~(ST0_CU3|ST0_CU2|ST0_CU1|ST0_KSU); + childregs->cp0_status &= ~(ST0_CU3|ST0_CU2|ST0_CU1); + + return 0; +} + +/* Fill in the fpu structure for a core dump.. */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r) +{ + /* We actually store the FPU info in the task->thread + * area. + */ + 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. */ +} + +/* Fill in the user structure for a core dump.. */ +void dump_thread(struct pt_regs *regs, struct user *dump) +{ + dump->magic = CMAGIC; + dump->start_code = current->mm->start_code; + dump->start_data = current->mm->start_data; + dump->start_stack = regs->regs[29] & ~(PAGE_SIZE - 1); + dump->u_tsize = (current->mm->end_code - dump->start_code) + >> PAGE_SHIFT; + dump->u_dsize = (current->mm->brk + (PAGE_SIZE - 1) - dump->start_data) + >> PAGE_SHIFT; + dump->u_ssize = (current->mm->start_stack - dump->start_stack + + PAGE_SIZE - 1) >> PAGE_SHIFT; + memcpy(&dump->regs[0], regs, sizeof(struct pt_regs)); + memcpy(&dump->regs[EF_SIZE/4], ¤t->thread.fpu, + sizeof(current->thread.fpu)); +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +{ + int retval; + + __asm__ __volatile__( + "move\t$6, $sp\n\t" + "move\t$4, %5\n\t" + "li\t$2, %1\n\t" + "syscall\n\t" + "beq\t$6, $sp, 1f\n\t" + "move\t$4, %3\n\t" + "jalr\t%4\n\t" + "move\t$4, $2\n\t" + "li\t$2, %2\n\t" + "syscall\n" + "1:\tmove\t%0, $2" + :"=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"); + + return retval; +} + +/* + * 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 schedule_frame; + unsigned long pc; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + pc = thread_saved_pc(&p->thread); + if (pc == (unsigned long) interruptible_sleep_on + || pc == (unsigned long) sleep_on) { + schedule_frame = ((unsigned long *)p->thread.reg30)[9]; + return ((unsigned long *)schedule_frame)[15]; + } + if (pc == (unsigned long) interruptible_sleep_on_timeout + || pc == (unsigned long) sleep_on_timeout) { + schedule_frame = ((unsigned long *)p->thread.reg30)[9]; + return ((unsigned long *)schedule_frame)[16]; + } + if (pc >= first_sched && pc < last_sched) { + printk(KERN_DEBUG "Bug in %s\n", __FUNCTION__); + } + + return pc; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/ptrace.c linux/arch/mips64/kernel/ptrace.c --- v2.3.47/linux/arch/mips64/kernel/ptrace.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/ptrace.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,37 @@ +/* $Id: ptrace.c,v 1.1 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1992 Ross Biro + * Copyright (C) Linus Torvalds + * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle + * Copyright (C) 1996 David S. Miller + * + * At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit + * binaries. + */ +#include +#include + + +asmlinkage void syscall_trace(void) +{ + if ((current->flags & (PF_PTRACED|PF_TRACESYS)) + != (PF_PTRACED|PF_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 -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/r4k_cache.S linux/arch/mips64/kernel/r4k_cache.S --- v2.3.47/linux/arch/mips64/kernel/r4k_cache.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/r4k_cache.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,28 @@ +/* $Id: r4k_cache.S,v 1.1 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995 - 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + * + * Cache error handler + */ +#include +#include +#include +#include + +/* + * Game over. Go to the button. Press gently. Swear where allowed by + * legislation. + */ + LEAF(except_vec2_generic) + /* Famous last words: unreached */ + mfc0 a1,CP0_ERROREPC + PRINT("Cache error exception: c0_errorepc == %08x\n") +1: + j 1b + nop + END(except_vec2_generic) diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/r4k_fpu.S linux/arch/mips64/kernel/r4k_fpu.S --- v2.3.47/linux/arch/mips64/kernel/r4k_fpu.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/r4k_fpu.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,149 @@ +/* $Id: r4k_fpu.S,v 1.1 1999/09/28 22:25: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. + * + * Save/restore floating point context for signal handlers. + * + * Copyright (C) 1996, 1998, 1999 by Ralf Baechle + * + * Multi-arch abstraction and asm macros for easier reading: + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include + + .macro EX insn, reg, src + .set push + .set nomacro +.ex\@: \insn \reg, \src + .set pop + .section __ex_table,"a" + PTR .ex\@, fault + .previous + .endm + + .set noreorder + /* Save floating point context */ +LEAF(save_fp_context) + mfc0 t1,CP0_STATUS + sll t2,t1,5 + + bgez t2,1f + cfc1 t1,fcr31 + /* Store the 16 odd double precision registers */ + EX sdc1 $f1, SC_FPREGS+8(a0) + EX sdc1 $f3, SC_FPREGS+24(a0) + EX sdc1 $f5, SC_FPREGS+40(a0) + EX sdc1 $f7, SC_FPREGS+56(a0) + EX sdc1 $f9, SC_FPREGS+72(a0) + EX sdc1 $f11, SC_FPREGS+88(a0) + EX sdc1 $f13, SC_FPREGS+104(a0) + EX sdc1 $f15, SC_FPREGS+120(a0) + EX sdc1 $f17, SC_FPREGS+136(a0) + EX sdc1 $f19, SC_FPREGS+152(a0) + EX sdc1 $f21, SC_FPREGS+168(a0) + EX sdc1 $f23, SC_FPREGS+184(a0) + EX sdc1 $f25, SC_FPREGS+200(a0) + EX sdc1 $f27, SC_FPREGS+216(a0) + EX sdc1 $f29, SC_FPREGS+232(a0) + EX sdc1 $f31, SC_FPREGS+248(a0) + + /* Store the 16 even double precision registers */ +1: + EX sdc1 $f0, SC_FPREGS+0(a0) + EX sdc1 $f2, SC_FPREGS+16(a0) + EX sdc1 $f4, SC_FPREGS+32(a0) + EX sdc1 $f6, SC_FPREGS+48(a0) + EX sdc1 $f8, SC_FPREGS+64(a0) + EX sdc1 $f10, SC_FPREGS+80(a0) + EX sdc1 $f12, SC_FPREGS+96(a0) + EX sdc1 $f14, SC_FPREGS+112(a0) + EX sdc1 $f16, SC_FPREGS+128(a0) + EX sdc1 $f18, SC_FPREGS+144(a0) + EX sdc1 $f20, SC_FPREGS+160(a0) + EX sdc1 $f22, SC_FPREGS+176(a0) + EX sdc1 $f24, SC_FPREGS+192(a0) + EX sdc1 $f26, SC_FPREGS+208(a0) + EX sdc1 $f28, SC_FPREGS+224(a0) + EX sdc1 $f30, SC_FPREGS+240(a0) + EX sw t1, SC_FPC_CSR(a0) + cfc1 t0,$0 # implementation/version + EX sw t0,SC_FPC_EIR(a0) + + jr ra + li v0, 0 # success + END(save_fp_context) + +/* + * Restore FPU state: + * - fp gp registers + * - cp1 status/control register + * + * We base the decision which registers to restore from the signal stack + * frame on the current content of c0_status, not on the content of the + * stack frame which might have been changed by the user. + */ +LEAF(restore_fp_context) + mfc0 t1, CP0_STATUS + sll t0,t1,5 + bgez t0,1f + EX lw t0, SC_FPC_CSR(a0) + + /* Restore the 16 odd double precision registers only + * when enabled in the cp0 status register. + */ + EX ldc1 $f1, SC_FPREGS+8(a0) + EX ldc1 $f3, SC_FPREGS+24(a0) + EX ldc1 $f5, SC_FPREGS+40(a0) + EX ldc1 $f7, SC_FPREGS+56(a0) + EX ldc1 $f9, SC_FPREGS+72(a0) + EX ldc1 $f11, SC_FPREGS+88(a0) + EX ldc1 $f13, SC_FPREGS+104(a0) + EX ldc1 $f15, SC_FPREGS+120(a0) + EX ldc1 $f17, SC_FPREGS+136(a0) + EX ldc1 $f19, SC_FPREGS+152(a0) + EX ldc1 $f21, SC_FPREGS+168(a0) + EX ldc1 $f23, SC_FPREGS+184(a0) + EX ldc1 $f25, SC_FPREGS+200(a0) + EX ldc1 $f27, SC_FPREGS+216(a0) + EX ldc1 $f29, SC_FPREGS+232(a0) + EX ldc1 $f31, SC_FPREGS+248(a0) + + /* + * Restore the 16 even double precision registers + * when cp1 was enabled in the cp0 status register. + */ +1: EX ldc1 $f0, SC_FPREGS+0(a0) + EX ldc1 $f2, SC_FPREGS+16(a0) + EX ldc1 $f4, SC_FPREGS+32(a0) + EX ldc1 $f6, SC_FPREGS+48(a0) + EX ldc1 $f8, SC_FPREGS+64(a0) + EX ldc1 $f10, SC_FPREGS+80(a0) + EX ldc1 $f12, SC_FPREGS+96(a0) + EX ldc1 $f14, SC_FPREGS+112(a0) + EX ldc1 $f16, SC_FPREGS+128(a0) + EX ldc1 $f18, SC_FPREGS+144(a0) + EX ldc1 $f20, SC_FPREGS+160(a0) + EX ldc1 $f22, SC_FPREGS+176(a0) + EX ldc1 $f24, SC_FPREGS+192(a0) + EX ldc1 $f26, SC_FPREGS+208(a0) + EX ldc1 $f28, SC_FPREGS+224(a0) + EX ldc1 $f30, SC_FPREGS+240(a0) + ctc1 t0,fcr31 + jr ra + li v0, 0 # success + END(restore_fp_context) + + .type fault@function + .ent fault +fault: li v0, -EFAULT + jr ra + .end fault diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/r4k_genex.S linux/arch/mips64/kernel/r4k_genex.S --- v2.3.47/linux/arch/mips64/kernel/r4k_genex.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/r4k_genex.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,168 @@ +/* $Id: r4k_genex.S,v 1.3 2000/01/20 23:32: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. + * + * Copyright (C) 1994 - 1999 by Ralf Baechle + * Copyright (C) 1999 Silicon Graphics + * + * Low level exception handling + */ +#define __ASSEMBLY__ +#include +#include +#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 + __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 */ + BUILD_HANDLER dbe dbe cli silent /* #7 */ + BUILD_HANDLER bp bp sti silent /* #9 */ + BUILD_HANDLER ri ri sti silent /* #10 */ + BUILD_HANDLER cpu cpu sti silent /* #11 */ + 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 */ + + __INIT + +/* General exception handler for CPUs with virtual coherency exception. + * + * Be careful when changing this, it has to be at most 128 bytes to fit + * into space reserved for the exception handler. + */ + 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 + dsll k1, k1, 1 + ld k0, exception_handlers(k1) + 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 # Is this ... + and k0, k1 # ... really needed? + mtc0 zero, CP0_TAGLO + cache Index_Store_Tag_D,(k0) + cache Hit_Writeback_Inv_SD,(k0) + lui k0, %hi(vced_count) + lw k1, %lo(vced_count)(k0) + addiu k1, 1 + sw k1, %lo(vced_count)(k0) + eret + +handle_vcei: + mfc0 k0, CP0_BADVADDR + cache Hit_Writeback_Inv_SD,(k0) # also cleans pi + lui k0, %hi(vcei_count) + lw k1, %lo(vcei_count)(k0) + addiu k1, 1 + sw k1, %lo(vcei_count)(k0) + eret + + END(except_vec3_r4000) + .set at + + /* General exception vector for all other CPUs. */ + NESTED(except_vec3_generic, 0, sp) + .set noat + mfc0 k1, CP0_CAUSE + andi k1, k1, 0x7c + dsll k1, k1, 1 + ld k0, exception_handlers(k1) + 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) + + __FINIT diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/r4k_switch.S linux/arch/mips64/kernel/r4k_switch.S --- v2.3.47/linux/arch/mips64/kernel/r4k_switch.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/r4k_switch.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,170 @@ +/* $Id: r4k_switch.S,v 1.1 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994, 1995, 1996, 1998, 1999 by Ralf Baechle + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1994, 1995, 1996, by Andreas Busse + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + .set mips3 + +/* + * task_struct *resume(task_struct *prev, task_struct *next) + */ + .set noreorder + .align 5 + LEAF(resume) + mfc0 t1, CP0_STATUS + sd t1, THREAD_STATUS(a0) + cpu_save_nonscratch a0 + sd ra, THREAD_REG31(a0) + + /* + * The order of restoring the registers takes care of the race + * updating $28, $29 and kernelsp without disabling ints. + */ + move $28, a1 + cpu_restore_nonscratch $28 + daddiu t0, $28, KERNEL_STACK_SIZE-32 + sd t0, kernelsp + mfc0 t1, CP0_STATUS /* Do we really need this? */ + li a3, 0xff00 + and t1, a3 + ld a2, THREAD_STATUS($28) + nor a3, $0, a3 + and a2, a3 + or a2, t1 + mtc0 a2, CP0_STATUS + jr ra + move v0, a0 + END(resume) + +/* + * Do lazy fpu context switch. Saves FPU context to the process in a0 + * and loads the new context of the current process. + */ + +#define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS) + +LEAF(lazy_fpu_switch) + mfc0 t0, CP0_STATUS # enable cp1 + li t3, 0x20000000 + or t0, t3 + mtc0 t0, CP0_STATUS + + beqz a0, 2f # Save floating point state + nor t3, zero, t3 + + lw t1, ST_OFF(a0) # last thread looses fpu + and t1, t3 + sd t1, ST_OFF(a0) + sll t2, t1, 5 + bgez t2, 1f + sdc1 $f0, (THREAD_FPU + 0x00)(a0) + fpu_save_16odd a0 +1: + fpu_save_16even a0 t1 # clobbers t1 +2: + + sll t0, t0, 5 # load new fp state + bgez t0, 1f + ldc1 $f0, (THREAD_FPU + 0x00)($28) + fpu_restore_16odd $28 +1: + .set reorder + fpu_restore_16even $28, t0 # clobbers t0 + jr ra + END(lazy_fpu_switch) + +/* + * Save a thread's fp context. + */ + .set noreorder +LEAF(save_fp) + mfc0 t0, CP0_STATUS + sll t1, t0, 5 + bgez t1, 1f # 16 register mode? + nop + fpu_save_16odd a0 +1: + fpu_save_16even a0 t1 # clobbers t1 + jr ra + sdc1 $f0, (THREAD_FPU + 0x00)(a0) + END(save_fp) + +/* + * Load the FPU with signalling NANS. This bit pattern we're using has + * the property that no matter whether considered as single or as double + * precision represents signaling NANS. + * + * We initialize fcr31 to rounding to nearest, no exceptions. + */ + +#define FPU_DEFAULT 0x00000000 + +LEAF(init_fpu) + mfc0 t0, CP0_STATUS + li t1, 0x20000000 + or t0, t1 + mtc0 t0, CP0_STATUS + sll t0, t0, 5 + + li t1, FPU_DEFAULT + ctc1 t1, fcr31 + + bgez t0, 1f # 16 / 32 register mode? + li t0, -1 + + dmtc1 t0, $f1 + dmtc1 t0, $f3 + dmtc1 t0, $f5 + dmtc1 t0, $f7 + dmtc1 t0, $f9 + dmtc1 t0, $f11 + dmtc1 t0, $f13 + dmtc1 t0, $f15 + dmtc1 t0, $f17 + dmtc1 t0, $f19 + dmtc1 t0, $f21 + dmtc1 t0, $f23 + dmtc1 t0, $f25 + dmtc1 t0, $f27 + dmtc1 t0, $f29 + dmtc1 t0, $f31 + +1: dmtc1 t0, $f0 + dmtc1 t0, $f2 + dmtc1 t0, $f4 + dmtc1 t0, $f6 + dmtc1 t0, $f8 + dmtc1 t0, $f10 + dmtc1 t0, $f12 + dmtc1 t0, $f14 + dmtc1 t0, $f16 + dmtc1 t0, $f18 + dmtc1 t0, $f20 + dmtc1 t0, $f22 + dmtc1 t0, $f24 + dmtc1 t0, $f26 + dmtc1 t0, $f28 + jr ra + dmtc1 t0, $f30 + END(init_fpu) diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/r4k_tlb_debug.c linux/arch/mips64/kernel/r4k_tlb_debug.c --- v2.3.47/linux/arch/mips64/kernel/r4k_tlb_debug.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/r4k_tlb_debug.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,72 @@ +/* $Id: r4k_tlb_debug.c,v 1.3 2000/01/29 01:41:59 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 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 -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/r4k_tlb_glue.S linux/arch/mips64/kernel/r4k_tlb_glue.S --- v2.3.47/linux/arch/mips64/kernel/r4k_tlb_glue.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/r4k_tlb_glue.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,42 @@ +/* $Id: r4k_tlb_glue.S,v 1.2 2000/01/17 23:32: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. + * + * Copyright (C) 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#define __ASSEMBLY__ +#include +#include +#include +#include + + __INIT +NESTED(__xtlb_refill_debug_tramp, PT_SIZE, sp) + j __xtlb_refill_debug + END(__xtlb_refill_debug_tramp) + +NESTED(__tlb_refill_debug_tramp, PT_SIZE, sp) + j __tlb_refill_debug + END(__tlb_refill_debug_tramp) + __FINIT + + .macro tlb_handler name + NESTED(__\name, PT_SIZE, sp) + SAVE_ALL + CLI + dmfc0 t0, CP0_BADVADDR + sd t0, PT_BVADDR(sp) + move a0, sp + jal \name + j return + END(__\name) + .endm + + tlb_handler tlb_refill_debug + tlb_handler xtlb_refill_debug + tlb_handler xtlb_mod_debug + tlb_handler xtlb_tlbl_debug + tlb_handler xtlb_tlbs_debug diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/scall_64.S linux/arch/mips64/kernel/scall_64.S --- v2.3.47/linux/arch/mips64/kernel/scall_64.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/scall_64.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,347 @@ +/* $Id: scall_64.S,v 1.7 2000/02/23 00:41:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1997, 1998, 1999 by Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* This duplicates the definition from */ +#define PF_TRACESYS 0x00000020 /* tracing system calls */ + +/* This duplicates the definition from */ +#define SIGILL 4 /* Illegal instruction (ANSI). */ + +/* Highest syscall handled here. */ +#define MAX_SYSCALL_NO __NR_Linux + __NR_Linux_syscalls + +#ifndef CONFIG_MIPS32_COMPAT +#define handle_sys64 handle_sys +#endif + + .align 5 +NESTED(handle_sys64, PT_SIZE, sp) +/* When 32-bit compatibility is configured scall_o32.S already did this. */ +#ifndef CONFIG_MIPS32_COMPAT + .set noat + SAVE_SOME + .set at +#endif + ld t1, PT_EPC(sp) # skip syscall on return + + sltiu t0, v0, MAX_SYSCALL_NO + 1 # check syscall number + daddiu t1, 4 # skip to next instruction + beqz t0, illegal_syscall + sd t1, PT_EPC(sp) + + dsll t0, v0, 3 + ld t2, (sys_call_table - (__NR_Linux * 8))(t0) # syscall routine + beqz t2, illegal_syscall; + + sd a3, PT_R26(sp) # save a3 for syscall restarting + + ld t0, TASK_FLAGS($28) # syscall tracing enabled? + andi t0, PF_TRACESYS + bnez t0, trace_a_syscall + + jalr t2 # Do The Real Thing (TM) + + li t0, -EMAXERRNO - 1 # error? + sltu t0, t0, v0 + sd t0, PT_R7(sp) # set error flag + beqz t0, 1f + + negu v0 # error + sd v0, PT_R0(sp) # set flag for syscall restarting +1: sd v0, PT_R2(sp) # result + +FEXPORT(ret_from_sys_call_64) + lw t0, softirq_state + lw t1, softirq_state+4 # unused delay slot + and t0, t1 + bnez t0, handle_softirq_64 + +9: ld t0, PT_STATUS(sp) # returning to kernel mode? + andi t1, t0, 0x10 + ld t2, TASK_NEED_RESCHED($28) + beqz t1, return_64 # -> yes + bnez t2, reschedule_64 + lw v0, TASK_SIGPENDING($28) + move a0, zero + beqz v0, return_64 + move a1, sp + SAVE_STATIC + jal do_signal + +return_64: + RESTORE_SOME + RESTORE_SP + .set mips3 + eret + .set mips0 + +handle_softirq_64: + jal do_softirq + b 9b +reschedule_64: + SAVE_STATIC + jal schedule + b ret_from_sys_call_64 + +/* ------------------------------------------------------------------------ */ + +trace_a_syscall: + SAVE_STATIC + sd t2,PT_R1(sp) + jal syscall_trace + ld t2,PT_R1(sp) + + ld a0, PT_R4(sp) # Restore argument registers + ld a1, PT_R5(sp) + ld a2, PT_R6(sp) + ld a3, PT_R7(sp) + jalr t2 + + li t0, -EMAXERRNO - 1 # error? + sltu t0, t0, v0 + sd t0, PT_R7(sp) # set error flag + beqz t0, 1f + + negu v0 # error + sd v0, PT_R0(sp) # set flag for syscall restarting +1: sd v0, PT_R2(sp) # result + + jal syscall_trace + j ret_from_sys_call + +illegal_syscall: + /* This also isn't a 64-bit syscall, throw an error. */ + li v0, ENOSYS # error + sd v0, PT_R2(sp) + li t0, 1 # set error flag + sd t0, PT_R7(sp) + j ret_from_sys_call + END(handle_sys64) + +sys_call_table: + PTR sys_syscall /* 4000 */ + PTR sys_exit + PTR sys_fork + PTR sys_read + PTR sys_write + PTR sys_open /* 4005 */ + PTR sys_close + PTR sys_waitpid + PTR sys_creat + PTR sys_link + PTR sys_unlink /* 4010 */ + PTR sys_execve + PTR sys_chdir + PTR sys_time + PTR sys_mknod + PTR sys_chmod /* 4015 */ + PTR sys_lchown + PTR sys_ni_syscall + PTR sys_stat + PTR sys_lseek + PTR sys_getpid /* 4020 */ + PTR sys_mount + PTR sys_oldumount + PTR sys_setuid + PTR sys_getuid + PTR sys_stime /* 4025 */ + PTR sys_ni_syscall /* ptrace */ + PTR sys_alarm + PTR sys_fstat + PTR sys_ni_syscall + PTR sys_utime /* 4030 */ + PTR sys_ni_syscall + PTR sys_ni_syscall + PTR sys_access + PTR sys_nice + PTR sys_ni_syscall /* 4035 */ + PTR sys_sync + PTR sys_kill + PTR sys_rename + PTR sys_mkdir + PTR sys_rmdir /* 4040 */ + PTR sys_dup + PTR sys_pipe + PTR sys_times + PTR sys_ni_syscall + PTR sys_brk /* 4045 */ + PTR sys_setgid + PTR sys_getgid + PTR sys_ni_syscall /* was signal 2 */ + PTR sys_geteuid + PTR sys_getegid /* 4050 */ + PTR sys_acct + PTR sys_umount + PTR sys_ni_syscall + PTR sys_ioctl + PTR sys_fcntl /* 4055 */ + PTR sys_ni_syscall + PTR sys_setpgid + PTR sys_ni_syscall + PTR sys_olduname + PTR sys_umask /* 4060 */ + PTR sys_chroot + PTR sys_ustat + PTR sys_dup2 + PTR sys_getppid + PTR sys_getpgrp /* 4065 */ + PTR sys_setsid + PTR sys_sigaction + PTR sys_sgetmask + PTR sys_ssetmask + PTR sys_setreuid /* 4070 */ + PTR sys_setregid + PTR sys_sigsuspend + PTR sys_sigpending + PTR sys_sethostname + PTR sys_setrlimit /* 4075 */ + PTR sys_getrlimit + PTR sys_getrusage + PTR sys_gettimeofday + PTR sys_settimeofday + PTR sys_getgroups /* 4080 */ + PTR sys_setgroups + PTR sys_ni_syscall /* old_select */ + PTR sys_symlink + PTR sys_lstat + PTR sys_readlink /* 4085 */ + PTR sys_uselib + PTR sys_swapon + PTR sys_reboot + PTR old_readdir + PTR sys_mmap /* 4090 */ + PTR sys_munmap + PTR sys_truncate + PTR sys_ftruncate + PTR sys_fchmod + PTR sys_fchown /* 4095 */ + PTR sys_getpriority + PTR sys_setpriority + PTR sys_ni_syscall + PTR sys_statfs + PTR sys_fstatfs /* 4100 */ + PTR sys_ni_syscall /* sys_ioperm */ + PTR sys_socketcall + PTR sys_syslog + PTR sys_setitimer + PTR sys_getitimer /* 4105 */ + PTR sys_newstat + PTR sys_newlstat + PTR sys_newfstat + PTR sys_uname + PTR sys_ni_syscall /* sys_ioperm *//* 4110 */ + PTR sys_vhangup + PTR sys_ni_syscall /* was sys_idle */ + PTR sys_ni_syscall /* sys_vm86 */ + PTR sys_wait4 + PTR sys_swapoff /* 4115 */ + PTR sys_sysinfo + PTR sys_ipc + PTR sys_fsync + PTR sys_sigreturn + PTR sys_clone /* 4120 */ + PTR sys_setdomainname + PTR sys_newuname + PTR sys_ni_syscall /* sys_modify_ldt */ + PTR sys_adjtimex + PTR sys_mprotect /* 4125 */ + PTR sys_sigprocmask + PTR sys_create_module + PTR sys_init_module + PTR sys_delete_module + PTR sys_get_kernel_syms /* 4130 */ + PTR sys_quotactl + PTR sys_getpgid + PTR sys_fchdir + PTR sys_bdflush + PTR sys_sysfs /* 4135 */ + PTR sys_personality + PTR sys_ni_syscall /* for afs_syscall */ + PTR sys_setfsuid + PTR sys_setfsgid + PTR sys_llseek /* 4140 */ + PTR sys_getdents + PTR sys_select + PTR sys_flock + PTR sys_msync + PTR sys_readv /* 4145 */ + PTR sys_writev + PTR sys_cacheflush + PTR sys_cachectl + PTR sys_sysmips + PTR sys_ni_syscall /* 4150 */ + PTR sys_getsid + PTR sys_fdatasync + PTR sys_sysctl + PTR sys_mlock + PTR sys_munlock /* 4155 */ + PTR sys_mlockall + PTR sys_munlockall + PTR sys_sched_setparam + PTR sys_sched_getparam + PTR sys_sched_setscheduler /* 4160 */ + PTR sys_sched_getscheduler + PTR sys_sched_yield + PTR sys_sched_get_priority_max + PTR sys_sched_get_priority_min + PTR sys_sched_rr_get_interval /* 4165 */ + PTR sys_nanosleep + PTR sys_mremap + PTR sys_accept + PTR sys_bind + PTR sys_connect /* 4170 */ + PTR sys_getpeername + PTR sys_getsockname + PTR sys_getsockopt + PTR sys_listen + PTR sys_recv /* 4175 */ + PTR sys_recvfrom + PTR sys_recvmsg + PTR sys_send + PTR sys_sendmsg + PTR sys_sendto /* 4180 */ + PTR sys_setsockopt + PTR sys_shutdown + PTR sys_socket + PTR sys_socketpair + PTR sys_setresuid /* 4185 */ + PTR sys_getresuid + PTR sys_query_module + PTR sys_poll + PTR sys_nfsservctl + PTR sys_setresgid /* 4190 */ + PTR sys_getresgid + PTR sys_prctl + PTR sys_rt_sigreturn + PTR sys_rt_sigaction + PTR sys_rt_sigprocmask /* 4195 */ + PTR sys_rt_sigpending + PTR sys_rt_sigtimedwait + PTR sys_rt_sigqueueinfo + PTR sys_rt_sigsuspend + PTR sys_pread /* 4200 */ + PTR sys_pwrite + PTR sys_chown + PTR sys_getcwd + PTR sys_capget + PTR sys_capset /* 4205 */ + PTR sys_sigaltstack + PTR sys_sendfile + PTR sys_ni_syscall + PTR sys_ni_syscall + PTR sys_pivot_root /* 4210 */ diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/scall_o32.S linux/arch/mips64/kernel/scall_o32.S --- v2.3.47/linux/arch/mips64/kernel/scall_o32.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/scall_o32.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,425 @@ +/* $Id: scall_o32.S,v 1.8 2000/02/23 00:41:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1997, 1998, 1999 by Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + * + * Hairy, the userspace application uses a different argument passing + * convention than the kernel, so we have to translate things from o32 + * to ABI64 calling convention. 64-bit syscalls are also processed + * here for now. + */ +#include +#include +#include +#include +#include +#include +#include + +/* This duplicates the definition from */ +#define PF_TRACESYS 0x00000020 /* tracing system calls */ + +/* This duplicates the definition from */ +#define SIGILL 4 /* Illegal instruction (ANSI). */ + +/* Highest syscall used of any syscall flavour */ +#define MAX_SYSCALL_NO __NR_Linux32 + __NR_Linux32_syscalls + + .align 5 +NESTED(handle_sys, PT_SIZE, sp) + .set noat + SAVE_SOME + STI + .set at + SAVE_ALL + ld a1, PT_R2(sp) + PRINT("Got syscall %d\n") + RESTORE_ALL + + ld t1, PT_EPC(sp) # skip syscall on return + + sltiu t0, v0, MAX_SYSCALL_NO + 1 # check syscall number + daddiu t1, 4 # skip to next instruction + beqz t0, not_o32_scall + sd t1, PT_EPC(sp) + + /* XXX Put both in one cacheline, should save a bit. */ + dsll t0, v0, 3 + ld t2, (sys_call_table - (__NR_Linux32 * 8))(t0) # syscall routine + lbu t3, (sys_narg_table - __NR_Linux32)(v0) # number of arguments + beqz t2, illegal_syscall; + + subu t0, t3, 5 # 5 or more arguments? + sd a3, PT_R26(sp) # save a3 for syscall restarting + bgez t0, stackargs + +stack_done: + ld t0, TASK_FLAGS($28) # syscall tracing enabled? + andi t0, PF_TRACESYS + bnez t0, trace_a_syscall + + jalr t2 # Do The Real Thing (TM) + + li t0, -EMAXERRNO - 1 # error? + sltu t0, t0, v0 + sd t0, PT_R7(sp) # set error flag + beqz t0, 1f + + negu v0 # error + sd v0, PT_R0(sp) # set flag for syscall restarting +1: sd v0, PT_R2(sp) # result + +FEXPORT(o32_ret_from_sys_call) + lw t0, softirq_state + lw t1, softirq_state+4 # unused delay slot + and t0, t1 + bnez t0, o32_handle_softirq + +9: ld t0,PT_STATUS(sp) # returning to kernel mode? + andi t1, t0, 0x10 + ld t2, TASK_NEED_RESCHED($28) + beqz t1, o32_return # -> yes + bnez t2, o32_reschedule + lw v0, TASK_SIGPENDING($28) + move a0, zero + beqz v0, o32_return + move a1, sp + SAVE_STATIC + jal do_signal + +o32_return: + RESTORE_SOME + RESTORE_SP + .set mips3 + eret + .set mips0 + +o32_handle_softirq: + jal do_softirq + b 9b +o32_reschedule: + SAVE_STATIC + jal schedule + b o32_ret_from_sys_call + +/* ------------------------------------------------------------------------ */ + +trace_a_syscall: + SAVE_STATIC + sd t2,PT_R1(sp) + jal syscall_trace + ld t2,PT_R1(sp) + + ld a0, PT_R4(sp) # Restore argument registers + ld a1, PT_R5(sp) + ld a2, PT_R6(sp) + ld a3, PT_R7(sp) + jalr t2 + + li t0, -EMAXERRNO - 1 # error? + sltu t0, t0, v0 + sd t0, PT_R7(sp) # set error flag + beqz t0, 1f + + negu v0 # error + sd v0, PT_R0(sp) # set flag for syscall restarting +1: sd v0, PT_R2(sp) # result + + jal syscall_trace + j ret_from_sys_call + +/* ------------------------------------------------------------------------ */ + + /* + * More than four arguments. Try to deal with it by copying the + * stack arguments from the user stack to the kernel stack. + * This Sucks (TM). + */ +stackargs: + ld t0, PT_R29(sp) # get old user stack pointer + subu t3, 4 + sll t1, t3, 2 # stack valid? + + addu t1, t0 # end address + or t0, t1 + bltz t0, bad_stack # -> sp is bad + + ld t0, PT_R29(sp) # get old user stack pointer + la t1, 3f # copy 1 to 2 arguments + sll t3, t3, 2 + subu t1, t3 + jr t1 + + /* Ok, copy the args from the luser stack to the kernel stack */ +1: lw a5, 20(t0) # argument #6 from usp +2: lw a4, 16(t0) # argument #5 from usp + +3: j stack_done # go back + + .section __ex_table,"a" + PTR 1b, bad_stack + PTR 2b, bad_stack + .previous + + /* + * The stackpointer for a call with more than 4 arguments is bad. + */ +bad_stack: + negu v0 # error + sd v0, PT_R0(sp) + sd v0, PT_R2(sp) + li t0, 1 # set error flag + sd t0, PT_R7(sp) + j ret_from_sys_call + +not_o32_scall: + /* This is not an 32-bit compatibility syscall, pass it on to + the 64-bit syscall handlers. */ + j handle_sys64 + +illegal_syscall: + /* This also isn't a 64-bit syscall, throw an error. */ + li v0, ENOSYS # error + sd v0, PT_R2(sp) + li t0, 1 # set error flag + sd t0, PT_R7(sp) + j ret_from_sys_call + END(handle_sys) + + .macro syscalltable + sys sys_syscall 0 /* 4000 */ + sys sys_exit 1 + sys sys_fork 0 + sys sys_read 3 + sys sys_write 3 + sys sys_open 3 /* 4005 */ + sys sys_close 3 + sys sys_waitpid 3 + sys sys_creat 2 + sys sys_link 2 + sys sys_unlink 1 /* 4010 */ + sys sys_execve 0 + sys sys_chdir 1 + sys sys_time 1 + sys sys_mknod 3 + sys sys_chmod 2 /* 4015 */ + sys sys_lchown 3 + sys sys_ni_syscall 0 + sys sys_stat 2 + sys sys_lseek 3 + sys sys_getpid 0 /* 4020 */ + sys sys_mount 5 + sys sys_oldumount 1 + sys sys_setuid 1 + sys sys_getuid 0 + sys sys_stime 1 /* 4025 */ + sys sys_ni_syscall 0 /* ptrace */ + sys sys_alarm 1 + sys sys_fstat 2 + sys sys_ni_syscall 0 + sys sys_utime 2 /* 4030 */ + sys sys_ni_syscall 0 + sys sys_ni_syscall 0 + sys sys_access 2 + sys sys_nice 1 + sys sys_ni_syscall 0 /* 4035 */ + sys sys_sync 0 + sys sys_kill 2 + sys sys_rename 2 + sys sys_mkdir 2 + sys sys_rmdir 1 /* 4040 */ + sys sys_dup 1 + sys sys_pipe 0 + sys sys_times 1 + sys sys_ni_syscall 0 + sys sys_brk 1 /* 4045 */ + sys sys_setgid 1 + sys sys_getgid 0 + sys sys_ni_syscall 0 /* was signal 2 */ + sys sys_geteuid 0 + sys sys_getegid 0 /* 4050 */ + sys sys_acct 0 + sys sys_umount 2 + sys sys_ni_syscall 0 + sys sys_ioctl 3 + sys sys_fcntl 3 /* 4055 */ + sys sys_ni_syscall 2 + sys sys_setpgid 2 + sys sys_ni_syscall, 0 + sys sys_olduname 1 + sys sys_umask 1 /* 4060 */ + sys sys_chroot 1 + sys sys_ustat 2 + sys sys_dup2 2 + sys sys_getppid 0 + sys sys_getpgrp 0 /* 4065 */ + sys sys_setsid 0 + sys sys32_sigaction 3 + sys sys_sgetmask 0 + sys sys_ssetmask 1 + sys sys_setreuid 2 /* 4070 */ + sys sys_setregid 2 + sys sys32_sigsuspend 0 + sys sys32_sigpending 1 + sys sys_sethostname 2 + sys sys_setrlimit 2 /* 4075 */ + sys sys_old_getrlimit 2 + sys sys_getrusage 2 + sys sys_gettimeofday 2 + sys sys_settimeofday 2 + sys sys_getgroups 2 /* 4080 */ + sys sys_setgroups 2 + sys sys_ni_syscall 0 /* old_select */ + sys sys_symlink 2 + sys sys_lstat 2 + sys sys_readlink 3 /* 4085 */ + sys sys_uselib 1 + sys sys_swapon 2 + sys sys_reboot 3 + sys old_readdir 3 + sys sys_mmap 6 /* 4090 */ + sys sys_munmap 2 + sys sys_truncate 2 + sys sys_ftruncate 2 + sys sys_fchmod 2 + sys sys_fchown 3 /* 4095 */ + sys sys_getpriority 2 + sys sys_setpriority 3 + sys sys_ni_syscall 0 + sys sys_statfs 2 + sys sys_fstatfs 2 /* 4100 */ + sys sys_ni_syscall 0 /* sys_ioperm */ + sys sys_socketcall 2 + sys sys_syslog 3 + sys sys_setitimer 3 + sys sys_getitimer 2 /* 4105 */ + sys sys32_newstat 2 + sys sys32_newlstat 2 + sys sys32_newfstat 2 + sys sys_uname 1 + sys sys_ni_syscall 0 /* sys_ioperm *//* 4110 */ + sys sys_vhangup 0 + sys sys_ni_syscall 0 /* was sys_idle */ + sys sys_ni_syscall 0 /* sys_vm86 */ + sys sys_wait4 4 + sys sys_swapoff 1 /* 4115 */ + sys sys_sysinfo 1 + sys sys_ipc 6 + sys sys_fsync 1 + sys sys32_sigreturn 0 + sys sys_clone 0 /* 4120 */ + sys sys_setdomainname 2 + sys sys_newuname 1 + sys sys_ni_syscall 0 /* sys_modify_ldt */ + sys sys_adjtimex 1 + sys sys_mprotect 3 /* 4125 */ + sys sys_sigprocmask 3 + sys sys_create_module 2 + sys sys_init_module 5 + sys sys_delete_module 1 + sys sys_get_kernel_syms 1 /* 4130 */ + sys sys_quotactl 0 + sys sys_getpgid 1 + sys sys_fchdir 1 + sys sys_bdflush 2 + sys sys_sysfs 3 /* 4135 */ + sys sys_personality 1 + sys sys_ni_syscall 0 /* for afs_syscall */ + sys sys_setfsuid 1 + sys sys_setfsgid 1 + sys sys_llseek 5 /* 4140 */ + sys sys_getdents 3 + sys sys_select 5 + sys sys_flock 2 + sys sys_msync 3 + sys sys_readv 3 /* 4145 */ + sys sys_writev 3 + sys sys_cacheflush 3 + sys sys_cachectl 3 + sys sys_sysmips 4 + sys sys_ni_syscall 0 /* 4150 */ + sys sys_getsid 1 + sys sys_fdatasync 0 + sys sys_sysctl 1 + sys sys_mlock 2 + sys sys_munlock 2 /* 4155 */ + sys sys_mlockall 1 + sys sys_munlockall 0 + sys sys_sched_setparam 2 + sys sys_sched_getparam 2 + sys sys_sched_setscheduler 3 /* 4160 */ + sys sys_sched_getscheduler 1 + sys sys_sched_yield 0 + sys sys_sched_get_priority_max 1 + sys sys_sched_get_priority_min 1 + sys sys_sched_rr_get_interval 2 /* 4165 */ + sys sys_nanosleep 2 + sys sys_mremap 4 + sys sys_accept 3 + sys sys_bind 3 + sys sys_connect 3 /* 4170 */ + sys sys_getpeername 3 + sys sys_getsockname 3 + sys sys_getsockopt 5 + sys sys_listen 2 + sys sys_recv 4 /* 4175 */ + sys sys_recvfrom 6 + sys sys_recvmsg 3 + sys sys_send 4 + sys sys_sendmsg 3 + sys sys_sendto 6 /* 4180 */ + sys sys_setsockopt 5 + sys sys_shutdown 2 + sys sys_socket 3 + sys sys_socketpair 4 + sys sys_setresuid 3 /* 4185 */ + sys sys_getresuid 3 + sys sys_query_module 5 + sys sys_poll 3 + sys sys_nfsservctl 3 + sys sys_setresgid 3 /* 4190 */ + sys sys_getresgid 3 + sys sys_prctl 5 + sys sys32_rt_sigreturn 0 + sys sys32_rt_sigaction 4 + sys sys32_rt_sigprocmask 4 /* 4195 */ + sys sys32_rt_sigpending 2 + sys sys32_rt_sigtimedwait 4 + sys sys32_rt_sigqueueinfo 3 + sys sys32_rt_sigsuspend 0 + sys sys_pread 4 /* 4200 */ + sys sys_pwrite 4 + sys sys_chown 3 + sys sys_getcwd 2 + sys sys_capget 2 + sys sys_capset 2 /* 4205 */ + sys sys32_sigaltstack 0 + sys sys_sendfile 3 + sys sys_ni_syscall 0 + sys sys_ni_syscall 0 + sys sys_mmap2 6 /* 4210 */ + sys sys_truncate64 2 + sys sys_ftruncate64 2 + sys sys_stat64 3 + sys sys_lstat64 3 + sys sys_fstat64 3 /* 4210 */ + sys sys_pivot_root 2 + .endm + + .macro sys function, nargs + PTR \function + .endm + +sys_call_table: + syscalltable + + .macro sys function, nargs + .byte \nargs + .endm + +sys_narg_table: + syscalltable diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/semaphore.c linux/arch/mips64/kernel/semaphore.c --- v2.3.47/linux/arch/mips64/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/semaphore.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,240 @@ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} + +/* + * RW Semaphores + */ +void +__down_read(struct rw_semaphore *sem, int count) +{ + DOWN_VAR; + + retry_down: + if (count < 0) { + /* Wait for the lock to become unbiased. Readers + are non-exclusive. */ + + /* This takes care of granting the lock. */ + up_read(sem); + + add_wait_queue(&sem->wait, &wait); + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (atomic_read(&sem->count) >= 0) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + mb(); + count = atomic_dec_return(&sem->count); + if (count <= 0) + goto retry_down; + } else { + add_wait_queue(&sem->wait, &wait); + + while (1) { + if (test_and_clear_bit(0, &sem->granted)) + break; + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if ((sem->granted & 1) == 0) + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + } +} + +void +__down_write(struct rw_semaphore *sem, int count) +{ + DOWN_VAR; + + retry_down: + if (count + RW_LOCK_BIAS < 0) { + up_write(sem); + + add_wait_queue_exclusive(&sem->wait, &wait); + + while (atomic_read(&sem->count) < 0) { + set_task_state(tsk, (TASK_UNINTERRUPTIBLE + | TASK_EXCLUSIVE)); + if (atomic_read(&sem->count) >= RW_LOCK_BIAS) + break; + schedule(); + } + + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + + mb(); + count = atomic_sub_return(RW_LOCK_BIAS, &sem->count); + if (count != 0) + goto retry_down; + } else { + /* Put ourselves at the end of the list. */ + add_wait_queue_exclusive(&sem->write_bias_wait, &wait); + + while (1) { + if (test_and_clear_bit(1, &sem->granted)) + break; + set_task_state(tsk, (TASK_UNINTERRUPTIBLE + | TASK_EXCLUSIVE)); + if ((sem->granted & 2) == 0) + schedule(); + } + + remove_wait_queue(&sem->write_bias_wait, &wait); + tsk->state = TASK_RUNNING; + + /* If the lock is currently unbiased, awaken the sleepers. + FIXME: This wakes up the readers early in a bit of a + stampede -> bad! */ + if (atomic_read(&sem->count) >= 0) + wake_up(&sem->wait); + } +} + +void +__rwsem_wake(struct rw_semaphore *sem, unsigned long readers) +{ + if (readers) { + if (test_and_set_bit(0, &sem->granted)) + BUG(); + wake_up(&sem->wait); + } else { + if (test_and_set_bit(1, &sem->granted)) + BUG(); + wake_up(&sem->write_bias_wait); + } +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/setup.c linux/arch/mips64/kernel/setup.c --- v2.3.47/linux/arch/mips64/kernel/setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/setup.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,186 @@ +/* $Id: setup.c,v 1.7 2000/02/04 07:40:24 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 Ralf Baechle + * Copyright (C) 1996 Stoned Elipot + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_RAM +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SGI_IP27 +#include +#endif + +struct mips_cpuinfo boot_cpu_data; + +#ifdef CONFIG_VT +struct screen_info screen_info; +#endif + +/* + * Not all of the MIPS CPUs have the "wait" instruction available. This + * is set to true if it is available. The wait instruction stops the + * pipeline and reduces the power consumption of the CPU very much. + */ +char wait_available; + +/* + * Do we have a cyclecounter available? + */ +char cyclecounter_available; + +/* + * Set if box has EISA slots. + */ +int EISA_bus = 0; + +#ifdef CONFIG_BLK_DEV_FD +extern struct fd_ops no_fd_ops; +struct fd_ops *fd_ops; +#endif + +#ifdef CONFIG_BLK_DEV_IDE +extern struct ide_ops no_ide_ops; +struct ide_ops *ide_ops; +#endif + +extern struct rtc_ops no_rtc_ops; +struct rtc_ops *rtc_ops; + +extern struct kbd_ops no_kbd_ops; +struct kbd_ops *kbd_ops; + +/* + * Setup information + * + * These are initialized so they are in the .data section + */ +unsigned long mips_memory_upper = KSEG0; +unsigned long mips_cputype = CPU_UNKNOWN; +unsigned long mips_machtype = MACH_UNKNOWN; +unsigned long mips_machgroup = MACH_GROUP_UNKNOWN; + +unsigned char aux_device_present; +extern int _end; + +extern void load_mmu(void); + +static char command_line[CL_SIZE] = { 0, }; + 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 = IO_BASE; + +extern void ip22_setup(void); +extern void ip27_setup(void); + +static inline void cpu_probe(void) +{ + unsigned int prid = read_32bit_cp0_register(CP0_PRID); + + switch(prid & 0xff00) { + case PRID_IMP_R4000: + if((prid & 0xff) == PRID_REV_R4400) + mips_cputype = CPU_R4400SC; + else + mips_cputype = CPU_R4000SC; + break; + case PRID_IMP_R4600: + mips_cputype = CPU_R4600; + break; + case PRID_IMP_R4700: + mips_cputype = CPU_R4700; + break; + case PRID_IMP_R5000: + mips_cputype = CPU_R5000; + break; + case PRID_IMP_NEVADA: + mips_cputype = CPU_NEVADA; + break; + case PRID_IMP_R8000: + mips_cputype = CPU_R8000; + break; + case PRID_IMP_R10000: + mips_cputype = CPU_R10000; + break; + default: + mips_cputype = CPU_UNKNOWN; + } +} + +void __init setup_arch(char **cmdline_p) +{ +#ifdef CONFIG_BLK_DEV_INITRD + unsigned long tmp; + unsigned long *initrd_header; +#endif + + cpu_probe(); + load_mmu(); + +#ifdef CONFIG_SGI_IP22 + ip22_setup(); +#endif +#ifdef CONFIG_SGI_IP27 + ip27_setup(); +#endif + + strncpy (command_line, arcs_cmdline, CL_SIZE); + memcpy(saved_command_line, command_line, CL_SIZE); + saved_command_line[CL_SIZE-1] = '\0'; + + *cmdline_p = command_line; + +#ifdef CONFIG_BLK_DEV_INITRD +#error "Initrd is broken, please fit it." + tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8; + if (tmp < (unsigned long)&_end) + tmp += PAGE_SIZE; + initrd_header = (unsigned long *)tmp; + if (initrd_header[0] == 0x494E5244) { + initrd_start = (unsigned long)&initrd_header[2]; + initrd_end = initrd_start + initrd_header[1]; + initrd_below_start_ok = 1; + if (initrd_end > memory_end) { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + initrd_end,memory_end); + initrd_start = 0; + } else + *memory_start_p = initrd_end; + } +#endif +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/signal.c linux/arch/mips64/kernel/signal.c --- v2.3.47/linux/arch/mips64/kernel/signal.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/signal.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,657 @@ +/* $Id: signal.c,v 1.5 2000/02/04 07:40:24 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1994 - 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#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))) + +extern asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, + int options, unsigned long *ru); +extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); +extern asmlinkage int save_fp_context(struct sigcontext *sc); +extern asmlinkage int restore_fp_context(struct sigcontext *sc); + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage inline int +sys_sigsuspend(abi64_no_regargs, struct pt_regs regs) +{ + sigset_t *uset, saveset, newset; + + save_static(®s); + uset = (sigset_t *) regs.regs[4]; + if (copy_from_user(&newset, uset, sizeof(sigset_t))) + 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.regs[2] = EINTR; + regs.regs[7] = 1; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, ®s)) + return -EINTR; + } +} + +asmlinkage int +sys_rt_sigsuspend(abi64_no_regargs, struct pt_regs regs) +{ + sigset_t *unewset, saveset, newset; + size_t sigsetsize; + + save_static(®s); + + /* XXX Don't preclude handling different sized sigset_t's. */ + sigsetsize = regs.regs[5]; + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + unewset = (sigset_t *) regs.regs[4]; + 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.regs[2] = EINTR; + regs.regs[7] = 1; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, ®s)) + return -EINTR; + } +} + +asmlinkage int +sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + int err = 0; + + if (act) { + old_sigset_t mask; + + if (!access_ok(VERIFY_READ, act, sizeof(*act))) + return -EFAULT; + err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); + err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + err |= __get_user(mask, &act->sa_mask.sig[0]); + err |= __get_user(new_ka.sa.sa_restorer, &act->sa_restorer); + if (err) + return -EFAULT; + + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) + return -EFAULT; + err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); + err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); + err |= __put_user(0, &oact->sa_mask.sig[1]); + err |= __put_user(0, &oact->sa_mask.sig[2]); + err |= __put_user(0, &oact->sa_mask.sig[3]); + err |= __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer); + if (err) + return -EFAULT; + } + + return ret; +} + +asmlinkage int +sys_sigaltstack(abi64_no_regargs, struct pt_regs regs) +{ + const stack_t *uss = (const stack_t *) regs.regs[4]; + stack_t *uoss = (stack_t *) regs.regs[5]; + unsigned long usp = regs.regs[29]; + + return do_sigaltstack(uss, uoss, usp); +} + +asmlinkage int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +{ + int owned_fp; + int err = 0; + + err |= __get_user(regs->cp0_epc, &sc->sc_pc); + err |= __get_user(regs->hi, &sc->sc_mdhi); + err |= __get_user(regs->lo, &sc->sc_mdlo); + +#define restore_gp_reg(i) do { \ + err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ +} 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); + restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); + restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); + restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); + restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); + restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); + restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); + restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); + restore_gp_reg(31); +#undef restore_gp_reg + + err |= __get_user(owned_fp, &sc->sc_ownedfp); + if (owned_fp) { + err |= restore_fp_context(sc); + last_task_used_math = current; + } + + return err; +} + +struct sigframe { + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_code[2]; /* signal trampoline */ + struct sigcontext sf_sc; + sigset_t sf_mask; +}; + +struct rt_sigframe { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_code[2]; /* signal trampoline */ + struct siginfo rs_info; + struct ucontext rs_uc; +}; + +asmlinkage void +sys_sigreturn(abi64_no_regargs, struct pt_regs regs) +{ + struct sigframe *frame; + sigset_t blocked; + + frame = (struct sigframe *) regs.regs[29]; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) + goto badframe; + + sigdelsetmask(&blocked, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = blocked; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext(®s, &frame->sf_sc)) + goto badframe; + + /* + * Don't let your children do this ... + */ + __asm__ __volatile__( + "move\t$29, %0\n\t" + "j\tret_from_sys_call" + :/* no outputs */ + :"r" (®s)); + /* Unreached */ + +badframe: + force_sig(SIGSEGV, current); +} + +asmlinkage void +sys_rt_sigreturn(abi64_no_regargs, struct pt_regs regs) +{ + struct rt_sigframe *frame; + sigset_t set; + stack_t st; + + frame = (struct rt_sigframe *) regs.regs[29]; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + goto badframe; + + if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs.regs[29]); + + /* + * Don't let your children do this ... + */ + __asm__ __volatile__( + "move\t$29, %0\n\t" + "j\tret_from_sys_call" + :/* no outputs */ + :"r" (®s)); + /* Unreached */ + +badframe: + force_sig(SIGSEGV, current); +} + +static int inline +setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +{ + int owned_fp; + int err = 0; + + err |= __put_user(regs->cp0_epc, &sc->sc_pc); + err |= __put_user(regs->cp0_status, &sc->sc_status); + +#define save_gp_reg(i) { \ + err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ +} while(0) + __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); + save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); + save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); + save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); + save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); + save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); + save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); + save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); + save_gp_reg(31); +#undef save_gp_reg + + err |= __put_user(regs->hi, &sc->sc_mdhi); + err |= __put_user(regs->lo, &sc->sc_mdlo); + err |= __put_user(regs->cp0_cause, &sc->sc_cause); + err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); + + owned_fp = (current == last_task_used_math); + err |= __put_user(owned_fp, &sc->sc_ownedfp); + + if (current->used_math) { /* fp is active. */ + set_cp0_status(ST0_CU1, ST0_CU1); + err |= save_fp_context(sc); + last_task_used_math = NULL; + regs->cp0_status &= ~ST0_CU1; + current->used_math = 0; + } + + return err; +} + +/* + * Determine which stack to use.. + */ +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +{ + unsigned long sp; + + /* Default to using normal stack */ + sp = regs->regs[29]; + + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void *)((sp - frame_size) & ALMASK); +} + +static void inline +setup_frame(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set) +{ + struct sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub already + in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) + regs->regs[31] = (unsigned long) ka->sa.sa_restorer; + else { + /* + * Set up the return code ... + * + * li v0, __NR_sigreturn + * syscall + */ + err |= __put_user(0x24020000 + __NR_sigreturn, + frame->sf_code + 0); + err |= __put_user(0x0000000c , + frame->sf_code + 1); + flush_cache_sigtramp((unsigned long) frame->sf_code); + } + + err |= setup_sigcontext(regs, &frame->sf_sc); + err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); + if (err) + goto give_sigsegv; + + /* + * Arguments to signal handler: + * + * a0 = signal number + * a1 = 0 (should be cause) + * a2 = pointer to struct sigcontext + * + * $25 and c0_epc point to the signal handler, $29 points to the + * struct sigframe. + */ + regs->regs[ 4] = signr; + regs->regs[ 5] = 0; + regs->regs[ 6] = (unsigned long) &frame->sf_sc; + regs->regs[29] = (unsigned long) frame; + regs->regs[31] = (unsigned long) frame->sf_code; + 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); +#endif + return; + +give_sigsegv: + if (signr == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static void inline +setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set, siginfo_t *info) +{ + struct rt_sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub already + in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) + regs->regs[31] = (unsigned long) ka->sa.sa_restorer; + else { + /* + * Set up the return code ... + * + * li v0, __NR_sigreturn + * syscall + */ + err |= __put_user(0x24020000 + __NR_sigreturn, + frame->rs_code + 0); + err |= __put_user(0x0000000c , + frame->rs_code + 1); + flush_cache_sigtramp((unsigned long) frame->rs_code); + } + + /* Create siginfo. */ + err |= __copy_to_user(&frame->rs_info, info, sizeof(*info)); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->rs_uc.uc_flags); + err |= __put_user(0, &frame->rs_uc.uc_link); + err |= __put_user((void *)current->sas_ss_sp, + &frame->rs_uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->regs[29]), + &frame->rs_uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, + &frame->rs_uc.uc_stack.ss_size); + err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); + err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); + + if (err) + goto give_sigsegv; + + /* + * Arguments to signal handler: + * + * a0 = signal number + * a1 = 0 (should be cause) + * a2 = pointer to ucontext + * + * $25 and c0_epc point to the signal handler, $29 points to + * the struct rt_sigframe. + */ + regs->regs[ 4] = signr; + regs->regs[ 5] = (unsigned long) &frame->rs_info; + regs->regs[ 6] = (unsigned long) &frame->rs_uc; + regs->regs[29] = (unsigned long) frame; + regs->regs[31] = (unsigned long) frame->rs_code; + 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); +#endif + return; + +give_sigsegv: + if (signr == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static inline void +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) +{ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(ka, regs, sig, oldset, info); + else + setup_frame(ka, regs, sig, oldset); + + 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); + } +} + +static inline void +syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) +{ + switch(regs->regs[0]) { + case ERESTARTNOHAND: + regs->regs[2] = EINTR; + break; + case ERESTARTSYS: + if(!(ka->sa.sa_flags & SA_RESTART)) { + regs->regs[2] = EINTR; + break; + } + /* fallthrough */ + case ERESTARTNOINTR: /* Userland will reload $v0. */ + regs->regs[7] = regs->regs[26]; + regs->cp0_epc -= 8; + } + + regs->regs[0] = 0; /* Don't deal with this again. */ +} + +extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs); +extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); + +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) +{ + struct k_sigaction *ka; + siginfo_t info; + +#ifdef CONFIG_BINFMT_ELF32 + if (current->thread.mflags & MF_32BIT) { + return do_signal32(oldset, regs); + } +#endif + +#ifdef CONFIG_BINFMT_IRIX + if (current->personality != PER_LINUX) + return do_irix_signal(oldset, regs); +#endif + + if (!oldset) + oldset = ¤t->blocked; + + for (;;) { + unsigned long signr; + + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + + if (!signr) + break; + + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ + current->exit_code = signr; + 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: + lock_kernel(); + sigaddset(¤t->signal, signr); + recalc_sigpending(current); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + if (regs->regs[0]) + syscall_restart(regs, ka); + /* Whee! Actually deliver the signal. */ + handle_signal(signr, ka, &info, oldset, regs); + return 1; + } + + /* + * Who's code doesn't conform to the restartable syscall convention + * dies here!!! The li instruction, a single machine instruction, + * must directly be followed by the syscall instruction. + */ + if (regs->regs[0]) { + if (regs->regs[2] == ERESTARTNOHAND || + regs->regs[2] == ERESTARTSYS || + regs->regs[2] == ERESTARTNOINTR) { + regs->regs[7] = regs->regs[26]; + regs->cp0_epc -= 8; + } + } + return 0; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/signal32.c linux/arch/mips64/kernel/signal32.c --- v2.3.47/linux/arch/mips64/kernel/signal32.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/signal32.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,688 @@ +/* $Id: signal32.c,v 1.2 2000/02/18 00:03:48 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1994 - 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#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))) + +extern asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, + int options, unsigned long *ru); +extern asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs); +extern asmlinkage int save_fp_context(struct sigcontext *sc); +extern asmlinkage int restore_fp_context(struct sigcontext *sc); + +/* 32-bit compatibility types */ + +#define _NSIG32 128 +#define _NSIG32_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef struct { + unsigned int sig[_NSIG_WORDS]; +} sigset32_t; + +typedef unsigned int __sighandler32_t; +typedef void (*vfptr_t)(void); + +struct sigaction32 { + unsigned int sa_flags; + __sighandler32_t sa_handler; + sigset32_t sa_mask; + unsigned int sa_restorer; + int sa_resv[1]; /* reserved */ +}; + +/* IRIX compatible stack_t */ +typedef struct sigaltstack32 { + void *ss_sp; + size_t ss_size; + int ss_flags; +} stack32_t; + + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage inline int +sys32_sigsuspend(abi64_no_regargs, struct pt_regs regs) +{ + sigset_t *uset, saveset, newset; + + save_static(®s); +printk("%s called.\n", __FUNCTION__); + uset = (sigset_t *) regs.regs[4]; + if (copy_from_user(&newset, uset, sizeof(sigset_t))) + 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.regs[2] = EINTR; + regs.regs[7] = 1; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal32(&saveset, ®s)) + return -EINTR; + } +} + +asmlinkage int +sys32_rt_sigsuspend(abi64_no_regargs, struct pt_regs regs) +{ + sigset_t *unewset, saveset, newset; + size_t sigsetsize; + + save_static(®s); +printk("%s called.\n", __FUNCTION__); + + /* XXX Don't preclude handling different sized sigset_t's. */ + sigsetsize = regs.regs[5]; + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + unewset = (sigset_t *) regs.regs[4]; + 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.regs[2] = EINTR; + regs.regs[7] = 1; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal32(&saveset, ®s)) + return -EINTR; + } +} + +asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, + struct sigaction32 *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + int err = 0; + + if (act) { + old_sigset_t mask; + + if (!access_ok(VERIFY_READ, act, sizeof(*act))) + return -EFAULT; + err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler); + err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); + err |= __get_user(mask, &act->sa_mask.sig[0]); + err |= __get_user(new_ka.sa.sa_restorer, &act->sa_restorer); + if (err) + return -EFAULT; + + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) + return -EFAULT; + err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); + err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); + err |= __put_user(0, &oact->sa_mask.sig[1]); + err |= __put_user(0, &oact->sa_mask.sig[2]); + err |= __put_user(0, &oact->sa_mask.sig[3]); + err |= __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer); + if (err) + return -EFAULT; + } + + return ret; +} + +asmlinkage int +sys32_sigaltstack(abi64_no_regargs, struct pt_regs regs) +{ + const stack_t *uss = (const stack_t *) regs.regs[4]; + stack_t *uoss = (stack_t *) regs.regs[5]; + unsigned long usp = regs.regs[29]; +printk("%s called.\n", __FUNCTION__); + + return do_sigaltstack(uss, uoss, usp); +} + +static asmlinkage int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +{ + int owned_fp; + int err = 0; + + err |= __get_user(regs->cp0_epc, &sc->sc_pc); + err |= __get_user(regs->hi, &sc->sc_mdhi); + err |= __get_user(regs->lo, &sc->sc_mdlo); + +#define restore_gp_reg(i) do { \ + err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ +} 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); + restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); + restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); + restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); + restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); + restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); + restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); + restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); + restore_gp_reg(31); +#undef restore_gp_reg + + err |= __get_user(owned_fp, &sc->sc_ownedfp); + if (owned_fp) { + err |= restore_fp_context(sc); + last_task_used_math = current; + } + + return err; +} + +struct sigframe { + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_code[2]; /* signal trampoline */ + struct sigcontext sf_sc; + sigset_t sf_mask; +}; + +struct rt_sigframe { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_code[2]; /* signal trampoline */ + struct siginfo rs_info; + struct ucontext rs_uc; +}; + +asmlinkage void +sys32_sigreturn(abi64_no_regargs, struct pt_regs regs) +{ + struct sigframe *frame; + sigset_t blocked; +printk("%s called.\n", __FUNCTION__); + + frame = (struct sigframe *) regs.regs[29]; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) + goto badframe; + + sigdelsetmask(&blocked, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = blocked; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext(®s, &frame->sf_sc)) + goto badframe; + + /* + * Don't let your children do this ... + */ + __asm__ __volatile__( + "move\t$29, %0\n\t" + "j\tret_from_sys_call" + :/* no outputs */ + :"r" (®s)); + /* Unreached */ + +badframe: + force_sig(SIGSEGV, current); +} + +asmlinkage void +sys32_rt_sigreturn(abi64_no_regargs, struct pt_regs regs) +{ + struct rt_sigframe *frame; + sigset_t set; + stack_t st; +printk("%s called.\n", __FUNCTION__); + + frame = (struct rt_sigframe *) regs.regs[29]; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext(®s, &frame->rs_uc.uc_mcontext)) + goto badframe; + + if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs.regs[29]); + + /* + * Don't let your children do this ... + */ + __asm__ __volatile__( + "move\t$29, %0\n\t" + "j\tret_from_sys_call" + :/* no outputs */ + :"r" (®s)); + /* Unreached */ + +badframe: + force_sig(SIGSEGV, current); +} + +static int inline +setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +{ + int owned_fp; + int err = 0; + + err |= __put_user(regs->cp0_epc, &sc->sc_pc); + err |= __put_user(regs->cp0_status, &sc->sc_status); + +#define save_gp_reg(i) { \ + err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ +} while(0) + __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); + save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); + save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); + save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); + save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); + save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); + save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); + save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); + save_gp_reg(31); +#undef save_gp_reg + + err |= __put_user(regs->hi, &sc->sc_mdhi); + err |= __put_user(regs->lo, &sc->sc_mdlo); + err |= __put_user(regs->cp0_cause, &sc->sc_cause); + err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); + + owned_fp = (current == last_task_used_math); + err |= __put_user(owned_fp, &sc->sc_ownedfp); + + if (current->used_math) { /* fp is active. */ + set_cp0_status(ST0_CU1, ST0_CU1); + err |= save_fp_context(sc); + last_task_used_math = NULL; + regs->cp0_status &= ~ST0_CU1; + current->used_math = 0; + } + + return err; +} + +/* + * Determine which stack to use.. + */ +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) +{ + unsigned long sp; + + /* Default to using normal stack */ + sp = regs->regs[29]; + + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void *)((sp - frame_size) & ALMASK); +} + +static void inline +setup_frame(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set) +{ + struct sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub already + in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) + regs->regs[31] = (unsigned long) ka->sa.sa_restorer; + else { + /* + * Set up the return code ... + * + * li v0, __NR_sigreturn + * syscall + */ + err |= __put_user(0x24020000 + __NR_sigreturn, + frame->sf_code + 0); + err |= __put_user(0x0000000c , + frame->sf_code + 1); + flush_cache_sigtramp((unsigned long) frame->sf_code); + } + + err |= setup_sigcontext(regs, &frame->sf_sc); + err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); + if (err) + goto give_sigsegv; + + /* + * Arguments to signal handler: + * + * a0 = signal number + * a1 = 0 (should be cause) + * a2 = pointer to struct sigcontext + * + * $25 and c0_epc point to the signal handler, $29 points to the + * struct sigframe. + */ + regs->regs[ 4] = signr; + regs->regs[ 5] = 0; + regs->regs[ 6] = (unsigned long) &frame->sf_sc; + regs->regs[29] = (unsigned long) frame; + regs->regs[31] = (unsigned long) frame->sf_code; + 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); +#endif + return; + +give_sigsegv: + if (signr == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static void inline +setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, + int signr, sigset_t *set, siginfo_t *info) +{ + struct rt_sigframe *frame; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub already + in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) + regs->regs[31] = (unsigned long) ka->sa.sa_restorer; + else { + /* + * Set up the return code ... + * + * li v0, __NR_sigreturn + * syscall + */ + err |= __put_user(0x24020000 + __NR_sigreturn, + frame->rs_code + 0); + err |= __put_user(0x0000000c , + frame->rs_code + 1); + flush_cache_sigtramp((unsigned long) frame->rs_code); + } + + /* Create siginfo. */ + err |= __copy_to_user(&frame->rs_info, info, sizeof(*info)); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->rs_uc.uc_flags); + err |= __put_user(0, &frame->rs_uc.uc_link); + err |= __put_user((void *)current->sas_ss_sp, + &frame->rs_uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->regs[29]), + &frame->rs_uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, + &frame->rs_uc.uc_stack.ss_size); + err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); + err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); + + if (err) + goto give_sigsegv; + + /* + * Arguments to signal handler: + * + * a0 = signal number + * a1 = 0 (should be cause) + * a2 = pointer to ucontext + * + * $25 and c0_epc point to the signal handler, $29 points to + * the struct rt_sigframe. + */ + regs->regs[ 4] = signr; + regs->regs[ 5] = (unsigned long) &frame->rs_info; + regs->regs[ 6] = (unsigned long) &frame->rs_uc; + regs->regs[29] = (unsigned long) frame; + regs->regs[31] = (unsigned long) frame->rs_code; + 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); +#endif + return; + +give_sigsegv: + if (signr == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static inline void +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) +{ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(ka, regs, sig, oldset, info); + else + setup_frame(ka, regs, sig, oldset); + + 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); + } +} + +static inline void +syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) +{ + switch(regs->regs[0]) { + case ERESTARTNOHAND: + regs->regs[2] = EINTR; + break; + case ERESTARTSYS: + if(!(ka->sa.sa_flags & SA_RESTART)) { + regs->regs[2] = EINTR; + break; + } + /* fallthrough */ + case ERESTARTNOINTR: /* Userland will reload $v0. */ + regs->regs[7] = regs->regs[26]; + regs->cp0_epc -= 8; + } + + regs->regs[0] = 0; /* Don't deal with this again. */ +} + +asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs) +{ + struct k_sigaction *ka; + siginfo_t info; +printk("%s: delivering signal.\n", current->comm); + + if (!oldset) + oldset = ¤t->blocked; + + for (;;) { + unsigned long signr; + + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + + if (!signr) + break; + + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ + current->exit_code = signr; + 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: + lock_kernel(); + sigaddset(¤t->signal, signr); + recalc_sigpending(current); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + if (regs->regs[0]) + syscall_restart(regs, ka); + /* Whee! Actually deliver the signal. */ +printk("%s: delivering signal.\n", __FUNCTION__); + handle_signal(signr, ka, &info, oldset, regs); + return 1; + } + + /* + * Who's code doesn't conform to the restartable syscall convention + * dies here!!! The li instruction, a single machine instruction, + * must directly be followed by the syscall instruction. + */ + if (regs->regs[0]) { + if (regs->regs[2] == ERESTARTNOHAND || + regs->regs[2] == ERESTARTSYS || + regs->regs[2] == ERESTARTNOINTR) { + regs->regs[7] = regs->regs[26]; + regs->cp0_epc -= 8; + } + } + return 0; +} + +/* Dummies ... */ + +asmlinkage void sys32_sigpending(void) { panic(__FUNCTION__ " called."); } +asmlinkage void sys32_rt_sigaction(void) { panic(__FUNCTION__ " called."); } +asmlinkage void sys32_rt_sigprocmask(void) { panic(__FUNCTION__ " called."); } +asmlinkage void sys32_rt_sigpending(void) { panic(__FUNCTION__ " called."); } +asmlinkage void sys32_rt_sigtimedwait(void) { panic(__FUNCTION__ " called."); } +asmlinkage void sys32_rt_sigqueueinfo(void) { panic(__FUNCTION__ " called."); } diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/softfp.S linux/arch/mips64/kernel/softfp.S --- v2.3.47/linux/arch/mips64/kernel/softfp.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/softfp.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,668 @@ +/* $Id: softfp.S,v 1.1 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1998, 1999 by Ralf Baechle + * Copyright (C) 1999 by Silicon Graphics, Inc. + * + * For now it's just a crude hack good enough to run certain fp programs like + * Mozilla. + * XXX: Handle MIPS II/III/IV/V enhancements, exceptions, ... + */ +#include +#include + +#ifndef __KERNEL__ +#define printk printf +#endif + +#define LOCK_KERNEL +#define UNLOCK_KERNEL + +/* + * This duplicates definitions from . + */ +#define KERN_EMERG "<0>" /* system is unusable */ +#define KERN_ALERT "<1>" /* action must be taken immediately */ +#define KERN_CRIT "<2>" /* critical conditions */ +#define KERN_ERR "<3>" /* error conditions */ +#define KERN_WARNING "<4>" /* warning conditions */ +#define KERN_NOTICE "<5>" /* normal but significant condition */ +#define KERN_INFO "<6>" /* informational */ +#define KERN_DEBUG "<7>" /* debug-level messages */ + +/* + * This duplicates definitions from + */ +#define SIGILL 4 /* Illegal instruction (ANSI). */ + +/* + * Definitions about the instruction format + */ +#define fd_shift 6 +#define fr_shift 21 +#define fs_shift 11 +#define ft_shift 16 + +/* + * NaNs as use by the MIPS architecture + */ +#define S_QNaN 0x7fbfffff +#define D_QNaN 0x7ff7ffffffffffff +#define W_QNaN 0x7fffffff +#define L_QNaN 0x7fffffffffffffff + +/* + * Checking for NaNs + */ +#define S_is_QNaN(reg,res) \ + sll res, reg, S_F_size - S_F_bits +#define D_is_QNaN(reg1,reg2,res) \ + sll res, reg1, (D_F_size - 32) - (D_F_bits - 32); \ + or res, reg2 + +/* + * Checking for Denorms + */ +#define S_is_Denorm(reg,res) \ + li res, 1 << (S_F_bits - 1); \ + and reg, res + +/* + * Some constants that define the properties of single precission numbers. + */ +#define S_M_prec 24 +#define S_E_max 127 +#define S_E_min -126 +#define S_E_bias 127 +#define S_E_bits 8 +#define S_F_bits 23 +#define S_F_size 32 + +/* Set temp0, if exponent of reg is S_E_max + 1. */ +#define S_is_E_max(reg,temp0,temp1) \ + li temp0, (S_E_max + 1 + S_E_bias) << S_F_bits; \ + and temp1, temp0, reg; \ + seq temp0, temp1 /* temp0 != 0 if NaN */ + +/* Clear temp0, if exponent of reg is S_E_min - 1. */ +#define S_is_E_min(reg,temp0) \ + li temp0, (S_E_min - 1 + S_E_bias) << S_F_bits; \ + and temp0, reg /* temp0 == 0 if denorm or zero */ + +/* Set temp0 if reg is a NaN assuming S_is_E_max is true */ +#define S_get_F(reg,temp0) \ + li temp0, (1 << S_F_bits) - 1; \ + and temp0, reg /* temp0 != 0 if NaN */ + +/* Set res if fraction of reg is != 0. */ +#define S_is_Inf(reg,res) \ + li res, (1 << S_F_bits) - 1; \ + and res, reg /* temp0 == 0 if Inf */ + + +/* + * Some constants that define the properties of double precission numbers. + */ +#define D_M_prec 53 +#define D_E_max 1023 +#define D_E_min -1022 +#define D_E_bias 1023 +#define D_E_bits 8 +#define D_F_bits 52 +#define D_F_size 64 + +/* Set temp0, if exponent of reg1/reg2 is D_E_max. */ +#define D_is_E_max(reg1,reg2,temp0,temp1) \ + li temp0, (D_E_max + 1 + D_E_bias) << (D_F_bits - 32); \ + and temp1, temp0, reg1; \ + seq temp0, temp1 /* temp0 != 0 if NaN */ + +/* Clear temp0, if exponent of reg is D_E_min. */ +#define D_is_E_min(reg1,reg2,res) \ + li res, (D_E_min + 1 + D_E_bias) << (D_F_bits - 32); \ + and res, reg1 /* temp0 == 0 if NaN or zero */ + +/* Set res if reg is a NaN assuming S_is_E_max is true */ +#define D_get_F(reg1,reg2,res) \ + li res, (1 << (D_F_bits - 32)) - 1; \ + and res, reg1 /* temp0 != 0 if NaN */ + +/* Set temp0 if reg1/reg2 is a NaN */ +#define D_is_NAN(reg1,reg2,temp0,temp1) \ + li temp0, (1 << (D_F_bits - 32) - 1; \ + and temp0, reg1; \ + or temp0, reg2; \ + sne temp0, zero, temp0 /* temp0 != 0 if NaN */ + +/* Set res if fraction of reg1/reg2 is != 0. */ +#define D_is_Inf(reg1,reg2,res) \ + li res, (1 << (D_F_bits - 32)) - 1; \ + and res, reg1; \ + or res, reg2 /* temp0 == 0 if Inf */ + +/* Complain about yet unhandled instruction. */ +#define BITCH(insn) \ +insn: LOCK_KERNEL; \ + la a1, 8f; \ + TEXT(#insn); \ + la a1, nosim; \ + UNLOCK_KERNEL; \ + j done + + .data +nosim: .asciz KERN_DEBUG "Don't know how to simulate %s instruction\n" + .previous + +/* + * When we come here, we've saved some of the integer registers and + * reenabled interrupts. + */ +LEAF(simfp) + .set noreorder + .cpload $25 + .set reorder + + subu sp, 16 + .cprestore 20 + sw ra, 16(sp) + + /* For now we assume that we get the opcode to simulate passed in as + an argument. */ + move ta0, a0 + + /* + * First table lookup using insn[5:0] + */ + la ta1, lowtab + andi ta2, ta0, 0x3f + sll ta2, ta2, 2 + addu ta1, ta2 + lw ta1, (ta1) + jr ta1 + END(simfp) + +/* + * We only decode the lower 3 of the 5 bit in the fmt field. That way we + * can keep the jump table significantly shorter. + */ +#define FMT_switch(insn,opc,temp0,temp1) \ +insn: srl temp0, opc, 19; \ + andi temp0, 0x1c; \ + la temp1, insn ## .tab; \ + addu temp0, temp1; \ + lw temp0, (temp0); \ + jr temp0; \ + \ + .data; \ +insn ## .tab: \ + .word insn ## .s, insn ## .d, unimp, unimp; \ + .word insn ## .w, insn ## .l, unimp, unimp; \ + .previous + + BITCH(add) + BITCH(sub) + BITCH(mul) + BITCH(div) + BITCH(sqrt) + BITCH(abs) + BITCH(mov) + BITCH(neg) + BITCH(round.l) + BITCH(trunc.l) + BITCH(ceil.l) + BITCH(floor.l) + BITCH(round.w) + BITCH(trunc.w) + BITCH(ceil.w) + BITCH(floor.w) + BITCH(cvt.s) + BITCH(cvt.d) + +/* ------------------------------------------------------------------------ */ + +FMT_switch(cvt.w,ta0,ta1,ta2) + +/* Convert a single fp to a fixed point integer. */ +cvt.w.s: + srl ta1, ta0, fs_shift # Get source register + andi ta1, 31 + jal s_get_fpreg + + S_is_E_max(ta1,ta2,ta3) + beqz ta2, 3f + /* Might be a NaN or Inf. */ + S_get_F(ta1,ta2) + beqz ta2, 2f + + /* It's a NaN. IEEE says undefined. */ + /* Is it a QNaN? Then the result is a QNaN as well. */ + S_is_QNaN(ta1,ta2) + bltz ta2, 1f + + /* XXX Ok, it's a SNaN. Signal invalid exception, if enabled. + For now we don't signal and supply a QNaN for result. */ + +1: li ta2, W_QNaN + srl ta1, ta0, fd_shift # Put result register + andi ta1, 31 + jal s_put_fpreg + j done +2: + + S_is_Inf(ta1,ta2) + bnez ta2, 2f + + /* It's +/- Inf. Set register to +/- max. integer. */ + /* XXX Send invalid operation exception instead, if enabled. */ + srl ta1, ta1, 31 # Extract sign bit + li ta2, 0x7fffffff + addu ta2, ta1 + + srl ta1, ta0, fd_shift # Put result register + andi ta1, 31 + jal s_put_fpreg + j done +2: +3: + + /* But then it might be a denorm or zero? */ + S_is_E_min(ta1,ta2) + bnez ta2, 2f + + /* Ok, it's a denorm or zero. */ + S_get_F(ta1,ta2) + beqz ta2, 1f + + /* It's a denorm. */ + /* XXX Should be signaling inexact exception, if enabled. */ + /* Fall through. */ +1: + /* Yes, it is a denorm or zero. Supply a zero as result. */ + move ta2, zero + srl ta1, ta0, fd_shift # Put result register + andi ta1, 31 + jal s_put_fpreg + j done +2: + + /* XXX Ok, it's a normal number. We don't handle that case yet. + If we have fp hardware this case is unreached. Add this for + full fp simulation. */ + + /* Done, return. */ + lw ra, 16(sp) + addu sp, 16 + jr ra + +/* Convert a double fp to a fixed point integer. */ +cvt.w.d: + srl ta1, ta0, fs_shift # Get source register + andi ta1, 31 + jal d_get_fpreg + + D_is_E_max(ta1,ta2,ta3,t0) + beqz ta3, 3f + + /* Might be a NaN or Inf. */ + D_get_F(ta1,ta2,ta3) + or ta3, ta2 + beqz ta3, 2f + + /* It's a NaN. IEEE says undefined. */ + /* Is it a QNaN? Then the result is a QNaN as well. */ + D_is_QNaN(ta1,ta2,ta3) + bltz ta3, 1f + + /* XXX Ok, it's a SNaN. Signal invalid exception, if enabled. + For now we don't signal and supply a QNaN for result. */ + +1: li ta2, W_QNaN + srl ta1, ta0, fd_shift # Put result register + andi ta1, 31 + jal s_put_fpreg + j done +2: + + D_is_Inf(ta1,ta2,ta3) + bnez ta3, 2f + + /* It's +/- Inf. Set register to +/- max. integer. */ + /* XXX Send invalid operation exception instead, if enabled. */ + srl ta1, ta1, 31 # Extract sign bit + li ta2, 0x7fffffff + addu ta2, ta1 + + srl ta1, ta0, fd_shift # Put result register + andi ta1, 31 + jal s_put_fpreg + j done +2: +3: + + /* But then it might be a denorm or zero? */ + D_is_E_min(ta1,ta2,ta3) + bnez ta3, 2f + + /* Ok, it's a denorm or zero. */ + D_get_F(ta1,ta2,ta3) + or ta3, ta2 + beqz ta3, 1f + + /* It's a denorm. */ + /* XXX Should be signaling inexact exception, if enabled. */ + /* Fall through. */ +1: + /* Yes, it is a denorm or zero. Supply a zero as result. */ + move ta2, zero + srl ta1, ta0, fd_shift # Put result register + andi ta1, 31 + jal s_put_fpreg + j done +2: + + /* XXX Ok, it's a normal number. We don't handle that case yet. + If we have fp hardware this case is only reached if the value + of the source register exceeds the range which is representable + in a single precission register. For now we kludge by returning + +/- maxint and don't signal overflow. */ + + srl ta1, ta1, 31 # Extract sign bit + li ta2, 0x7fffffff + addu ta2, ta1 + + srl ta1, ta0, fd_shift # Put result register + andi ta1, 31 + jal s_put_fpreg + + /* Done, return. */ + lw ra, 16(sp) + addu sp, 16 + jr ra + +cvt.w.w = unimp # undefined result +cvt.w.l = unimp # undefined result + +/* MIPS III extension, no need to handle for 32bit OS. */ +cvt.l = unimp + +/* ------------------------------------------------------------------------ */ + + BITCH(c.f) + BITCH(c.un) + BITCH(c.eq) + BITCH(c.ueq) + BITCH(c.olt) + BITCH(c.ult) + BITCH(c.ole) + BITCH(c.ule) + BITCH(c.sf) + BITCH(c.ngle) + BITCH(c.seq) + BITCH(c.ngl) + BITCH(c.lt) + BITCH(c.nge) + BITCH(c.le) + BITCH(c.ngt) + +/* Get the single precission register which's number is in ta1. */ +s_get_fpreg: + .set noat + sll AT, ta1, 2 + sll ta1, 3 + addu ta1, AT + la AT, 1f + addu AT, ta1 + jr AT + .set at + +1: mfc1 ta1, $0 + jr ra + mfc1 ta1, $1 + jr ra + mfc1 ta1, $2 + jr ra + mfc1 ta1, $3 + jr ra + mfc1 ta1, $4 + jr ra + mfc1 ta1, $5 + jr ra + mfc1 ta1, $6 + jr ra + mfc1 ta1, $7 + jr ra + mfc1 ta1, $8 + jr ra + mfc1 ta1, $9 + jr ra + mfc1 ta1, $10 + jr ra + mfc1 ta1, $11 + jr ra + mfc1 ta1, $12 + jr ra + mfc1 ta1, $13 + jr ra + mfc1 ta1, $14 + jr ra + mfc1 ta1, $15 + jr ra + mfc1 ta1, $16 + jr ra + mfc1 ta1, $17 + jr ra + mfc1 ta1, $18 + jr ra + mfc1 ta1, $19 + jr ra + mfc1 ta1, $20 + jr ra + mfc1 ta1, $21 + jr ra + mfc1 ta1, $22 + jr ra + mfc1 ta1, $23 + jr ra + mfc1 ta1, $24 + jr ra + mfc1 ta1, $25 + jr ra + mfc1 ta1, $26 + jr ra + mfc1 ta1, $27 + jr ra + mfc1 ta1, $28 + jr ra + mfc1 ta1, $29 + jr ra + mfc1 ta1, $30 + jr ra + mfc1 ta1, $31 + jr ra + +/* + * Put the value in ta2 into the single precission register which's number + * is in ta1. + */ +s_put_fpreg: + .set noat + sll AT, ta1, 2 + sll ta1, 3 + addu ta1, AT + la AT, 1f + addu AT, ta1 + jr AT + .set at + +1: mtc1 ta2, $0 + jr ra + mtc1 ta2, $1 + jr ra + mtc1 ta2, $2 + jr ra + mtc1 ta2, $3 + jr ra + mtc1 ta2, $4 + jr ra + mtc1 ta2, $5 + jr ra + mtc1 ta2, $6 + jr ra + mtc1 ta2, $7 + jr ra + mtc1 ta2, $8 + jr ra + mtc1 ta2, $9 + jr ra + mtc1 ta2, $10 + jr ra + mtc1 ta2, $11 + jr ra + mtc1 ta2, $12 + jr ra + mtc1 ta2, $13 + jr ra + mtc1 ta2, $14 + jr ra + mtc1 ta2, $15 + jr ra + mtc1 ta2, $16 + jr ra + mtc1 ta2, $17 + jr ra + mtc1 ta2, $18 + jr ra + mtc1 ta2, $19 + jr ra + mtc1 ta2, $20 + jr ra + mtc1 ta2, $21 + jr ra + mtc1 ta2, $22 + jr ra + mtc1 ta2, $23 + jr ra + mtc1 ta2, $24 + jr ra + mtc1 ta2, $25 + jr ra + mtc1 ta2, $26 + jr ra + mtc1 ta2, $27 + jr ra + mtc1 ta2, $28 + jr ra + mtc1 ta2, $29 + jr ra + mtc1 ta2, $30 + jr ra + mtc1 ta2, $31 + jr ra + +/* Get the double precission register which's number is in ta1 into ta1/ta2. */ +d_get_fpreg: + .set noat + sll ta1, 3 + la AT, 1f + addu AT, ta1 + jr AT + .set at + +1: mfc1 ta1, $0 + mfc1 ta2, $1 + jr ra + mfc1 ta1, $2 + mfc1 ta2, $3 + jr ra + mfc1 ta1, $4 + mfc1 ta2, $5 + jr ra + mfc1 ta1, $6 + mfc1 ta2, $7 + jr ra + mfc1 ta1, $8 + mfc1 ta2, $9 + jr ra + mfc1 ta1, $10 + mfc1 ta2, $11 + jr ra + mfc1 ta1, $12 + mfc1 ta2, $13 + jr ra + mfc1 ta1, $14 + mfc1 ta2, $15 + jr ra + mfc1 ta1, $16 + mfc1 ta2, $17 + jr ra + mfc1 ta1, $18 + mfc1 ta2, $19 + jr ra + mfc1 ta1, $20 + mfc1 ta2, $21 + jr ra + mfc1 ta1, $22 + mfc1 ta2, $23 + jr ra + mfc1 ta1, $24 + mfc1 ta2, $25 + jr ra + mfc1 ta1, $26 + mfc1 ta2, $27 + jr ra + mfc1 ta1, $28 + mfc1 ta2, $29 + jr ra + mfc1 ta1, $30 + mfc1 ta2, $31 + jr ra + +/* + * Send an invalid operation exception. + */ +invalid: + lw ra, 16(sp) + addu sp, 16 + jr ra + +/* + * Done, just skip over the current instruction + */ +done: + lw ra, 16(sp) + addu sp, 16 + jr ra + +unimp: + /* We've run into an yet unknown instruction. This happens either + on new, yet unsupported CPU types or when the faulting instruction + is being executed for cache but has been overwritten in memory. */ + LOCK_KERNEL + move a0, ta0 + PRINT(KERN_DEBUG "FP support: unknown fp op %08lx, ") + PRINT("please mail to ralf@gnu.org.\n") + UNLOCK_KERNEL + + li a0, SIGILL # Die, sucker ... + move a1, $28 + jal force_sig + + lw ra, 16(sp) + addu sp, 16 + jr ra + +/* + * Jump table for the lowest 6 bits of a cp1 instruction. + */ + .data +lowtab: .word add, sub, mul, div, sqrt, abs, mov, neg + .word round.l,trunc.l,ceil.l,floor.l,round.w,trunc.w,ceil.w,floor.w + .word unimp, unimp, unimp, unimp, unimp, unimp, unimp, unimp + .word unimp, unimp, unimp, unimp, unimp, unimp, unimp, unimp + .word cvt.s, cvt.d, unimp, unimp, cvt.w, cvt.l, unimp, unimp + .word unimp, unimp, unimp, unimp, unimp, unimp, unimp, unimp + .word c.f, c.un, c.eq, c.ueq, c.olt, c.ult, c.ole, c.ule + .word c.sf, c.ngle,c.seq, c.ngl, c.lt, c.nge, c.le, c.ngt diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/syscall.c linux/arch/mips64/kernel/syscall.c --- v2.3.47/linux/arch/mips64/kernel/syscall.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/syscall.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,326 @@ +/* $Id: syscall.c,v 1.3 2000/02/04 07:40:24 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995 - 1999 by Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +asmlinkage int sys_pipe(abi64_no_regargs, struct pt_regs regs) +{ + int fd[2]; + int error, res; + + lock_kernel(); + error = do_pipe(fd); + if (error) { + res = error; + goto out; + } + regs.regs[3] = fd[1]; + res = fd[0]; +out: + unlock_kernel(); + return res; +} + +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 error = -EFAULT; + + down(¤t->mm->mmap_sem); + lock_kernel(); + if (!(flags & MAP_ANONYMOUS)) { + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + } + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + error = do_mmap(file, addr, len, prot, flags, offset); + if (file) + fput(file); +out: + unlock_kernel(); + up(¤t->mm->mmap_sem); + + return error; +} + +asmlinkage int sys_fork(abi64_no_regargs, struct pt_regs regs) +{ + int res; + + save_static(®s); + res = do_fork(SIGCHLD, regs.regs[29], ®s); + return res; +} + +asmlinkage int sys_clone(abi64_no_regargs, struct pt_regs regs) +{ + unsigned long clone_flags; + unsigned long newsp; + int res; + + save_static(®s); + clone_flags = regs.regs[4]; + newsp = regs.regs[5]; + if (!newsp) + newsp = regs.regs[29]; + res = do_fork(clone_flags, newsp, ®s); + return res; +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(abi64_no_regargs, struct pt_regs regs) +{ + int error; + char * filename; + + lock_kernel(); + filename = getname((char *) (long)regs.regs[4]); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, (char **) (long)regs.regs[5], + (char **) (long)regs.regs[6], ®s); + putname(filename); + +out: + unlock_kernel(); + return error; +} + +/* + * Compacrapability ... + */ +asmlinkage int sys_uname(struct old_utsname * name) +{ + if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + return 0; + return -EFAULT; +} + +/* + * Compacrapability ... + */ +asmlinkage int sys_olduname(struct oldold_utsname * name) +{ + int error; + + if (!name) + return -EFAULT; + if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) + return -EFAULT; + + 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); + error = error ? -EFAULT : 0; + + return error; +} + +/* + * Do the indirect syscall syscall. + * + * XXX This is borken. + */ +asmlinkage int sys_syscall(abi64_no_regargs, struct pt_regs regs) +{ + return -ENOSYS; +} + +asmlinkage int +sys_sysmips(int cmd, long arg1, int arg2, int arg3) +{ + int *p; + char *name; + int flags, tmp, len, errno; + + switch(cmd) + { + case SETNAME: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + name = (char *) arg1; + len = strlen_user(name); + + if (len == 0 || len > __NEW_UTS_LEN) + return -EINVAL; + down(&uts_sem); + errno = -EFAULT; + if (!copy_from_user(system_utsname.nodename, name, len)) { + system_utsname.nodename[len] = '\0'; + errno = 0; + } + up(&uts_sem); + return errno; + + case MIPS_ATOMIC_SET: + /* This is broken in case of page faults and SMP ... + Risc/OS fauls after maximum 20 tries with EAGAIN. */ + p = (int *) arg1; + errno = verify_area(VERIFY_WRITE, p, sizeof(*p)); + if (errno) + return errno; + save_and_cli(flags); + errno = *p; + *p = arg2; + restore_flags(flags); + + return errno; /* This is broken ... */ + + case MIPS_FIXADE: + tmp = current->thread.mflags & ~3; + current->thread.mflags = tmp | (arg1 & 3); + return 0; + + case FLUSH_CACHE: + flush_cache_all(); + return 0; + + case MIPS_RDNVRAM: + return -EIO; + } + + return -EINVAL; +} + +/* + * 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, + int third, void *ptr, long fifth) +{ + int version, ret; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void **) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + + if (copy_from_user(&tmp, + (struct ipc_kludge *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, (struct msqid_ds *) ptr); + + case SHMAT: + switch (version) { + default: { + ulong raddr; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong *) third); + } + case 1: /* iBCS2 emulator entry point */ + if (!segment_eq(get_fs(), get_ds())) + return -EINVAL; + return sys_shmat (first, (char *) ptr, second, (ulong *) third); + } + case SHMDT: + return sys_shmdt ((char *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds *) ptr); + default: + return -EINVAL; + } +} + +/* + * No implemented yet ... + */ +asmlinkage int +sys_cachectl(char *addr, int nbytes, int op) +{ + return -ENOSYS; +} + +/* + * If we ever come here the user sp is bad. Zap the process right away. + * Due to the bad stack signaling wouldn't work. + */ +asmlinkage void bad_stack(void) +{ + do_exit(SIGSEGV); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/traps.c linux/arch/mips64/kernel/traps.c --- v2.3.47/linux/arch/mips64/kernel/traps.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/traps.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,565 @@ +/* $Id: traps.c,v 1.5 2000/02/24 00:12:41 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994 - 1999 by Ralf Baechle + * Copyright (C) 1995, 1996 Paul M. Antoine + * Copyright (C) 1998 Ulf Carlsson + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int console_loglevel; + +static inline void console_silent(void) +{ + console_loglevel = 0; +} + +static inline void console_verbose(void) +{ + if (console_loglevel) + console_loglevel = 15; +} + +extern asmlinkage void __xtlb_mod_debug(void); +extern asmlinkage void __xtlb_tlbl_debug(void); +extern asmlinkage void __xtlb_tlbs_debug(void); +extern asmlinkage void handle_adel(void); +extern asmlinkage void handle_ades(void); +extern asmlinkage void handle_ibe(void); +extern asmlinkage void handle_dbe(void); +extern asmlinkage void handle_sys(void); +extern asmlinkage void handle_bp(void); +extern asmlinkage void handle_ri(void); +extern asmlinkage void handle_cpu(void); +extern asmlinkage void handle_ov(void); +extern asmlinkage void handle_tr(void); +extern asmlinkage void handle_fpe(void); +extern asmlinkage void handle_watch(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; + +/* + * These constant is for searching for possible module text segments. + * MODULE_RANGE is a guess of how much space is likely to be vmalloced. + */ +#define MODULE_RANGE (8*1024*1024) + +/* + * This routine abuses get_user()/put_user() to reference pointers + * with at least a bit of error checking ... + */ +void show_stack(unsigned int *sp) +{ + int i; + unsigned int *stack; + + stack = sp; + i = 0; + + printk("Stack:"); + while ((unsigned long) stack & (PAGE_SIZE - 1)) { + unsigned long stackdata; + + if (__get_user(stackdata, stack++)) { + printk(" (Bad stack address)"); + break; + } + + printk(" %08lx", stackdata); + + if (++i > 40) { + printk(" ..."); + break; + } + + if (i % 8 == 0) + printk("\n "); + } +} + +void show_trace(unsigned int *sp) +{ + int i; + unsigned int *stack; + unsigned long kernel_start, kernel_end; + unsigned long module_start, module_end; + extern char _stext, _etext; + + stack = sp; + i = 0; + + kernel_start = (unsigned long) &_stext; + kernel_end = (unsigned long) &_etext; + module_start = VMALLOC_START; + module_end = module_start + MODULE_RANGE; + + printk("\nCall Trace:"); + + while ((unsigned long) stack & (PAGE_SIZE -1)) { + unsigned long addr; + + if (__get_user(addr, stack++)) { + printk(" (Bad stack address)\n"); + break; + } + + /* + * 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 >= kernel_start && addr < kernel_end) || + (addr >= module_start && addr < module_end)) { + + printk(" [<%08lx>]", addr); + if (++i > 40) { + printk(" ..."); + break; + } + } + } +} + +void show_code(unsigned int *pc) +{ + long i; + + printk("\nCode:"); + + for(i = -3 ; i < 6 ; i++) { + unsigned long insn; + if (__get_user(insn, pc + i)) { + printk(" (Bad address in epc)\n"); + break; + } + printk("%c%08lx%c",(i?' ':'<'),insn,(i?' ':'>')); + } +} + +spinlock_t die_lock; + +void die(const char * str, struct pt_regs * regs, unsigned long err) +{ + 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); + show_regs(regs); + printk("Process %s (pid: %ld, stackpage=%08lx)\n", + current->comm, current->pid, (unsigned long) current); + show_stack((unsigned int *) regs->regs[29]); + show_trace((unsigned int *) regs->regs[29]); + show_code((unsigned int *) regs->cp0_epc); + printk("\n"); + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +} + +void die_if_kernel(const char * str, struct pt_regs * regs, unsigned long err) +{ + if (!user_mode(regs)) + die(str, regs, err); +} + +void do_ov(struct pt_regs *regs) +{ + if (compute_return_epc(regs)) + return; + force_sig(SIGFPE, current); +} + +#ifdef CONFIG_MIPS_FPE_MODULE +static void (*fpe_handler)(struct pt_regs *regs, unsigned int fcr31); + +/* + * Register_fpe/unregister_fpe are for debugging purposes only. To make + * this hack work a bit better there is no error checking. + */ +int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31)) +{ + fpe_handler = handler; + return 0; +} + +int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31)) +{ + fpe_handler = NULL; + return 0; +} +#endif + +/* + * XXX Delayed fp exceptions when doing a lazy ctx switch XXX + */ +void do_fpe(struct pt_regs *regs, unsigned long fcr31) +{ + unsigned long pc; + unsigned int insn; + +#ifdef CONFIG_MIPS_FPE_MODULE + if (fpe_handler != NULL) { + fpe_handler(regs, fcr31); + return; + } +#endif + lock_kernel(); + if (fcr31 & 0x20000) { + /* Retry instruction with flush to zero ... */ + if (!(fcr31 & (1<<24))) { + printk("Setting flush to zero for %s.\n", + current->comm); + fcr31 &= ~0x20000; + fcr31 |= (1<<24); + __asm__ __volatile__( + "ctc1\t%0,$31" + : /* No outputs */ + : "r" (fcr31)); + goto out; + } + pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0); + if (get_user(insn, (unsigned int *)pc)) { + /* XXX Can this happen? */ + force_sig(SIGSEGV, current); + } + + printk(KERN_DEBUG "Unimplemented exception for insn %08x at 0x%08lx in %s.\n", + insn, regs->cp0_epc, current->comm); + simfp(insn); + } + + if (compute_return_epc(regs)) + goto out; + //force_sig(SIGFPE, current); + printk(KERN_DEBUG "Should send SIGFPE to %s\n", current->comm); + +out: + unlock_kernel(); +} + +static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) +{ + unsigned int *epc; + + epc = (unsigned int *) (unsigned long) regs->cp0_epc; + if (regs->cp0_cause & CAUSEF_BD) + epc += 4; + + if (verify_area(VERIFY_READ, epc, 4)) { + force_sig(SIGSEGV, current); + return 1; + } + *opcode = *epc; + + return 0; +} + +void do_bp(struct pt_regs *regs) +{ + unsigned int opcode, bcode; + + /* + * There is the ancient bug in the MIPS assemblers that the break + * code starts left to bit 16 instead to bit 6 in the opcode. + * Gas is bug-compatible ... + */ + if (get_insn_opcode(regs, &opcode)) + return; + bcode = ((opcode >> 16) & ((1 << 20) - 1)); + + /* + * (A short test says that IRIX 5.3 sends SIGTRAP for all break + * insns, even for break codes that indicate arithmetic failures. + * Weird ...) + */ + force_sig(SIGTRAP, current); +} + +void do_tr(struct pt_regs *regs) +{ + unsigned int opcode, bcode; + + if (get_insn_opcode(regs, &opcode)) + return; + bcode = ((opcode >> 6) & ((1 << 20) - 1)); + + /* + * (A short test says that IRIX 5.3 sends SIGTRAP for all break + * insns, even for break codes that indicate arithmetic failures. + * Wiered ...) + */ + force_sig(SIGTRAP, current); +} + +void do_ri(struct pt_regs *regs) +{ + lock_kernel(); + printk("[%s:%ld] Illegal instruction at %08lx ra=%08lx\n", + current->comm, current->pid, regs->cp0_epc, regs->regs[31]); + unlock_kernel(); + if (compute_return_epc(regs)) + return; + force_sig(SIGILL, current); +} + +void do_cpu(struct pt_regs *regs) +{ + u32 cpid; + + cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; + if (cpid != 1) + goto bad_cid; + + regs->cp0_status |= ST0_CU1; + if (last_task_used_math == current) + return; + + if (current->used_math) { /* Using the FPU again. */ + lazy_fpu_switch(last_task_used_math); + } else { /* First time FPU user. */ + init_fpu(); + current->used_math = 1; + } + last_task_used_math = current; + return; + +bad_cid: + force_sig(SIGILL, current); +} + +void do_watch(struct pt_regs *regs) +{ + /* + * We use the watch exception where available to detect stack + * overflows. + */ + show_regs(regs); + panic("Caught WATCH exception - probably caused by stack overflow."); +} + +void do_reserved(struct pt_regs *regs) +{ + /* + * Game over - no way to handle this if it ever occurs. Most probably + * caused by a new unknown cpu type or after another deadly + * hard/software error. + */ + panic("Caught reserved exception %d - should not happen.", + (regs->cp0_cause & 0x1f) >> 2); +} + +static inline void watch_init(unsigned long cputype) +{ + switch(cputype) { + case CPU_R10000: + case CPU_R4000MC: + case CPU_R4400MC: + case CPU_R4000SC: + case CPU_R4400SC: + case CPU_R4000PC: + case CPU_R4400PC: + case CPU_R4200: + case CPU_R4300: + set_except_vector(23, handle_watch); + watch_available = 1; + break; + } +} + +/* + * 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]; + +/* + * As a side effect of the way this is implemented we're limited + * to interrupt handlers in the address range from + * KSEG0 <= x < KSEG0 + 256mb on the Nevada. Oh well ... + */ +void set_except_vector(int n, void *addr) +{ + unsigned long handler = (unsigned long) addr; + exception_handlers[n] = handler; + if (n == 0 && dedicated_iv_available) { + *(volatile u32 *)(KSEG0+0x200) = 0x08000000 | + (0x03ffffff & (handler >> 2)); + flush_icache_range(KSEG0+0x200, KSEG0 + 0x204); + } +} + +static inline void mips4_setup(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); + } + mips4_available = 0; +} + +static inline void go_64(void) +{ + unsigned int bits; + + bits = ST0_KX|ST0_SX|ST0_UX; + set_cp0_status(bits, bits); + printk("Entering 64-bit mode.\n"); +} + +void __init trap_init(void) +{ + extern char __tlb_refill_debug_tramp; + extern char __xtlb_refill_debug_tramp; + extern char except_vec2_generic; + extern char except_vec3_generic, except_vec3_r4000; + extern void bus_error_init(void); + unsigned long i; + + /* Some firmware leaves the BEV flag set, clear it. */ + set_cp0_status(ST0_BEV, 0); + + /* Copy the generic exception handler code to it's final destination. */ + memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80); + memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x80); + + /* + * Setup default vectors + */ + for(i = 0; i <= 31; i++) + set_except_vector(i, handle_reserved); + + /* + * 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 ;-) */ + + /* + * 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; + + 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: + case CPU_R4300: + case CPU_R4600: + case CPU_R5000: + case CPU_NEVADA: +r4k: + /* Debug TLB refill handler. */ + memcpy((void *)KSEG0, &__tlb_refill_debug_tramp, 0x80); + memcpy((void *)KSEG0 + 0x080, &__xtlb_refill_debug_tramp, 0x80); + + /* Cache error vector */ + memcpy((void *)(KSEG0 + 0x100), (void *) KSEG0, 0x80); + + if (vce_available) { + memcpy((void *)(KSEG0 + 0x180), &except_vec3_r4000, + 0x180); + } else { + memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, + 0x100); + } + + set_except_vector(1, __xtlb_mod_debug); + set_except_vector(2, __xtlb_tlbl_debug); + set_except_vector(3, __xtlb_tlbs_debug); + set_except_vector(4, handle_adel); + set_except_vector(5, handle_ades); + + /* DBE / IBE exception handler are system specific. */ + bus_error_init(); + + set_except_vector(8, handle_sys); + set_except_vector(9, handle_bp); + set_except_vector(10, handle_ri); + set_except_vector(11, handle_cpu); + set_except_vector(12, handle_ov); + set_except_vector(13, handle_tr); + set_except_vector(15, handle_fpe); + break; + + case CPU_R8000: + panic("unsupported CPU type %s.\n", cpu_names[mips_cputype]); + break; + + case CPU_UNKNOWN: + default: + panic("Unknown CPU type"); + } + flush_icache_range(KSEG0, KSEG0 + 0x200); + + atomic_inc(&init_mm.mm_count); /* XXX UP? */ + current->active_mm = &init_mm; + current_pgd = init_mm.pgd; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/kernel/unaligned.c linux/arch/mips64/kernel/unaligned.c --- v2.3.47/linux/arch/mips64/kernel/unaligned.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/kernel/unaligned.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,405 @@ +/* $Id: unaligned.c,v 1.2 2000/01/17 23:32:46 ralf Exp $ + * + * Handle unaligned accesses by emulation. + * + * 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, 1998, 1999 by Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + * + * This file contains exception handler for address error exception with the + * special capability to execute faulting instructions in software. The + * handler does not try to handle the case when the program counter points + * to an address not aligned to a word boundary. + * + * Putting data to unaligned addresses is a bad practice even on Intel where + * only the performance is affected. Much worse is that such code is non- + * portable. Due to several programs that die on MIPS due to alignment + * problems I decided to implement this handler anyway though I originally + * didn't intend to do this at all for user code. + * + * For now I enable fixing of address errors by default to make life easier. + * I however intend to disable this somewhen in the future when the alignment + * problems with user programs have been fixed. For programmers this is the + * right way to go. + * + * Fixing address errors is a per process option. The option is inherited + * across fork(2) and execve(2) calls. If you really want to use the + * option in your user programs - I discourage the use of the software + * emulation strongly - use the following code in your userland stuff: + * + * #include + * + * ... + * sysmips(MIPS_FIXADE, x); + * ... + * + * The argument x is 0 for disabling software emulation, enabled otherwise. + * + * Below a little program to play around with this feature. + * + * #include + * #include + * + * struct foo { + * unsigned char bar[8]; + * }; + * + * main(int argc, char *argv[]) + * { + * struct foo x = {0, 1, 2, 3, 4, 5, 6, 7}; + * unsigned int *p = (unsigned int *) (x.bar + 3); + * int i; + * + * if (argc > 1) + * sysmips(MIPS_FIXADE, atoi(argv[1])); + * + * printf("*p = %08lx\n", *p); + * + * *p = 0xdeadface; + * + * for(i = 0; i <= 7; i++) + * printf("%02x ", x.bar[i]); + * printf("\n"); + * } + * + * Coprocessor loads are not supported; I think this case is unimportant + * in the practice. + * + * TODO: Handle ndc (attempted store to doubleword in uncached memory) + * exception for the R6000. + * A store crossing a page boundary might be executed only partially. + * Undo the partial store in this case. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define STR(x) __STR(x) +#define __STR(x) #x + +/* + * User code may only access USEG; kernel code may access the + * entire address space. + */ +#define check_axs(p,a,s) \ + 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) +{ + union mips_instruction insn; + unsigned long value, fixup; + + regs->regs[0] = 0; + /* + * This load never faults. + */ + __get_user(insn.word, (unsigned int *)pc); + + switch (insn.i_format.opcode) { + /* + * These are instructions that a compiler doesn't generate. We + * can assume therefore that the code is MIPS-aware and + * really buggy. Emulating these instructions would break the + * semantics anyway. + */ + case ll_op: + case lld_op: + case sc_op: + case scd_op: + + /* + * For these instructions the only way to create an address + * error is an attempted access to kernel/supervisor address + * space. + */ + case ldl_op: + case ldr_op: + case lwl_op: + case lwr_op: + case sdl_op: + case sdr_op: + case swl_op: + case swr_op: + case lb_op: + case lbu_op: + case sb_op: + goto sigbus; + + /* + * The remaining opcodes are the ones that are really of interest. + */ + case lh_op: + check_axs(pc, addr, 2); + __asm__( + ".set\tnoat\n" +#ifdef __BIG_ENDIAN + "1:\tlb\t%0,0(%1)\n" + "2:\tlbu\t$1,1(%1)\n\t" +#endif +#ifdef __LITTLE_ENDIAN + "1:\tlb\t%0,1(%1)\n" + "2:\tlbu\t$1,0(%1)\n\t" +#endif + "sll\t%0,0x8\n\t" + "or\t%0,$1\n\t" + ".set\tat\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) + :"$1"); + regs->regs[insn.i_format.rt] = value; + return; + + 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" +#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)); + regs->regs[insn.i_format.rt] = value; + return; + + 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" +#endif +#ifdef __LITTLE_ENDIAN + "1:\tlbu\t%0,1(%1)\n" + "2:\tlbu\t$1,0(%1)\n\t" +#endif + "sll\t%0,0x8\n\t" + "or\t%0,$1\n\t" + ".set\tat\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) + :"$1"); + regs->regs[insn.i_format.rt] = value; + return; + + 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; + + case sh_op: + check_axs(pc, addr, 2); + value = regs->regs[insn.i_format.rt]; + __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" + ".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" + ".set\tat\n\t" +#endif + ".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) + :"$1"); + return; + + 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" +#endif +#ifdef __LITTLE_ENDIAN + "1:\tswl\t%0,3(%1)\n" + "2:\tswr\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" + : /* no outputs */ + :"r" (value), "r" (addr), "i" (&&fault)); + return; + + 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; + + case lwc1_op: + case ldc1_op: + case swc1_op: + case sdc1_op: + /* + * I herewith declare: this does not happen. So send SIGBUS. + */ + goto sigbus; + + case lwc2_op: + case ldc2_op: + case swc2_op: + case sdc2_op: + /* + * These are the coprocessor 2 load/stores. The current + * implementations don't use cp2 and cp2 should always be + * disabled in c0_status. So send SIGILL. + * (No longer true: The Sony Praystation uses cp2 for + * 3D matrix operations. Dunno if that thingy has a MMU ...) + */ + default: + /* + * Pheeee... We encountered an yet unknown instruction or + * cache coherence problem. Die sucker, die ... + */ + goto sigill; + } + return; + +fault: + /* Did we have an exception handler installed? */ + fixup = search_exception_table(regs->cp0_epc); + if (fixup) { + long new_epc; + new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc); + printk(KERN_DEBUG "%s: Forwarding exception at [<%lx>] (%lx)\n", + current->comm, regs->cp0_epc, new_epc); + regs->cp0_epc = new_epc; + return; + } + + send_sig(SIGSEGV, current, 1); + return; +sigbus: + send_sig(SIGBUS, current, 1); + return; +sigill: + send_sig(SIGILL, current, 1); + return; +} + +unsigned long unaligned_instructions; + +asmlinkage void do_ade(struct pt_regs *regs) +{ + unsigned long pc; + + /* + * Did we catch a fault trying to load an instruction? + * This also catches attempts to activate MIPS16 code on + * CPUs which don't support it. + */ + if (regs->cp0_badvaddr == regs->cp0_epc) + 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); + unaligned_instructions++; + + return; + +sigbus: + force_sig(SIGBUS, current); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/ld.script.elf32 linux/arch/mips64/ld.script.elf32 --- v2.3.47/linux/arch/mips64/ld.script.elf32 Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/ld.script.elf32 Thu Feb 24 22:53:35 2000 @@ -0,0 +1,110 @@ +OUTPUT_ARCH(mips) +ENTRY(kernel_entry) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0x80000000; + .init : { *(.init) } =0 + .text : + { + _ftext = . ; + *(.text) + *(.rodata) + *(.rodata1) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0 + _etext = .; + PROVIDE (etext = .); + + . = ALIGN(16384); + .data.init_task : { *(.data.init_task) } + + /* Startup code */ + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(4096); /* Align double page for init_task_union */ + __init_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + .fini : { *(.fini) } =0 + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. It would + be more correct to do this: + . = .; + The current expression does not correctly handle the case of a + text segment ending precisely at the end of a page; it causes the + data segment to skip a page. The above expression does not have + this problem, but it will currently (2/95) cause BFD to allocate + a single segment, combining both text and data, for this case. + This will prevent the text segment from being shared among + multiple executions of the program; I think that is more + important than losing a page of the virtual address space (note + that no actual memory is lost; the page which is skipped can not + be referenced). */ + . = .; + .data : + { + _fdata = . ; + *(.data) + CONSTRUCTORS + } + .data1 : { *(.data1) } + _gp = . + 0x8000; + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + + __bss_start = .; + _fbss = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + _end = . ; + PROVIDE (end = .); + } + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the .debug DWARF section are relative to the beginning of the + section so we begin .debug at 0. It's not clear yet what needs to happen + for the others. */ + .debug 0 : { *(.debug) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .line 0 : { *(.line) } + /* These must appear regardless of . */ + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/ld.script.elf64 linux/arch/mips64/ld.script.elf64 --- v2.3.47/linux/arch/mips64/ld.script.elf64 Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/ld.script.elf64 Thu Feb 24 22:53:35 2000 @@ -0,0 +1,119 @@ +OUTPUT_ARCH(mips) +ENTRY(kernel_entry) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + /* . = 0xc000000000000000; */ + + /* This is the value for an Origin kernel, taken from an IRIX kernel. */ + /* . = 0xc00000000001c000; */ + + /* Set the vaddr for the text segment to a value + >= 0xa800 0000 0001 9000 if no symmon is going to configured + >= 0xa800 0000 0030 0000 otherwise */ + + /* . = 0xa800000000300000; */ + /* . = 0xa800000000300000; */ + . = 0xffffffff80300000; + .text : { + _ftext = . ; + *(.text) + *(.rodata) + *(.rodata1) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } = 0 + _etext = .; + PROVIDE (etext = .); + + . = ALIGN(16384); + .data.init_task : { *(.data.init_task) } + + /* Startup code */ + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(4096); /* Align double page for init_task_union */ + __init_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + .fini : { *(.fini) } =0 + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. It would + be more correct to do this: + . = .; + The current expression does not correctly handle the case of a + text segment ending precisely at the end of a page; it causes the + data segment to skip a page. The above expression does not have + this problem, but it will currently (2/95) cause BFD to allocate + a single segment, combining both text and data, for this case. + This will prevent the text segment from being shared among + multiple executions of the program; I think that is more + important than losing a page of the virtual address space (note + that no actual memory is lost; the page which is skipped can not + be referenced). */ + . = .; + .data : + { + _fdata = . ; + *(.data) + CONSTRUCTORS + } + .data1 : { *(.data1) } + _gp = . + 0x8000; + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + + __bss_start = .; + _fbss = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + _end = . ; + PROVIDE (end = .); + } + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the .debug DWARF section are relative to the beginning of the + section so we begin .debug at 0. It's not clear yet what needs to happen + for the others. */ + .debug 0 : { *(.debug) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .line 0 : { *(.line) } + /* These must appear regardless of . */ + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/Makefile linux/arch/mips64/lib/Makefile --- v2.3.47/linux/arch/mips64/lib/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/Makefile Thu Feb 24 22:53:35 2000 @@ -0,0 +1,17 @@ +# $Id: Makefile,v 1.2 1999/12/04 03:59:00 ralf Exp $ +# +# Makefile for MIPS-specific library files.. +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +L_TARGET = lib.a +L_OBJS = 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 \ + rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o \ + strnlen_user.o watch.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/csum_partial.S linux/arch/mips64/lib/csum_partial.S --- v2.3.47/linux/arch/mips64/lib/csum_partial.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/csum_partial.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,243 @@ +/* $Id: csum_partial.S,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Quick'n'dirty IP checksum ... + * + * Copyright (C) 1998, 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include + +#define ADDC(sum,reg) \ + addu sum, reg; \ + sltu v1, sum, reg; \ + addu sum, v1 + +#define CSUM_BIGCHUNK(src, offset, sum, t0, t1, t2, t3) \ + lw t0, (offset + 0x00)(src); \ + lw t1, (offset + 0x04)(src); \ + lw t2, (offset + 0x08)(src); \ + lw t3, (offset + 0x0c)(src); \ + ADDC(sum, t0); \ + ADDC(sum, t1); \ + ADDC(sum, t2); \ + ADDC(sum, t3); \ + lw t0, (offset + 0x10)(src); \ + lw t1, (offset + 0x14)(src); \ + lw t2, (offset + 0x18)(src); \ + lw t3, (offset + 0x1c)(src); \ + ADDC(sum, t0); \ + ADDC(sum, t1); \ + ADDC(sum, t2); \ + ADDC(sum, t3); \ + +/* + * a0: source address + * a1: length of the area to checksum + * a2: partial checksum + */ + +#define src a0 +#define sum v0 + + .text + .set noreorder + +/* unknown src alignment and < 8 bytes to go */ +small_csumcpy: + move a1, ta2 + + andi ta0, a1, 4 + beqz ta0, 1f + andi ta0, a1, 2 + + /* Still a full word to go */ + ulw ta1, (src) + daddiu src, 4 + ADDC(sum, ta1) + +1: move ta1, zero + beqz ta0, 1f + andi ta0, a1, 1 + + /* Still a halfword to go */ + ulhu ta1, (src) + daddiu src, 2 + +1: beqz ta0, 1f + sll ta1, ta1, 16 + + lbu ta2, (src) + nop + +#ifdef __MIPSEB__ + sll ta2, ta2, 8 +#endif + or ta1, ta2 + +1: ADDC(sum, ta1) + + /* fold checksum */ + sll v1, sum, 16 + addu sum, v1 + sltu v1, sum, v1 + srl sum, sum, 16 + addu sum, v1 + + /* odd buffer alignment? */ + beqz t3, 1f + nop + sll v1, sum, 8 + srl sum, sum, 8 + or sum, v1 + andi sum, 0xffff +1: + .set reorder + /* Add the passed partial csum. */ + ADDC(sum, a2) + jr ra + .set noreorder + +/* ------------------------------------------------------------------------- */ + + .align 5 +LEAF(csum_partial) + move sum, zero + move t3, zero + + sltiu t8, a1, 0x8 + bnez t8, small_csumcpy /* < 8 bytes to copy */ + move ta2, a1 + + beqz a1, out + andi t3, src, 0x1 /* odd buffer? */ + +hword_align: + beqz t3, word_align + andi t8, src, 0x2 + + lbu ta0, (src) + dsubu a1, a1, 0x1 +#ifdef __MIPSEL__ + sll ta0, ta0, 8 +#endif + ADDC(sum, ta0) + daddu src, src, 0x1 + andi t8, src, 0x2 + +word_align: + beqz t8, dword_align + sltiu t8, a1, 56 + + lhu ta0, (src) + dsubu a1, a1, 0x2 + ADDC(sum, ta0) + sltiu t8, a1, 56 + daddu src, src, 0x2 + +dword_align: + bnez t8, do_end_words + move t8, a1 + + andi t8, src, 0x4 + beqz t8, qword_align + andi t8, src, 0x8 + + lw ta0, 0x00(src) + dsubu a1, a1, 0x4 + ADDC(sum, ta0) + daddu src, src, 0x4 + andi t8, src, 0x8 + +qword_align: + beqz t8, oword_align + andi t8, src, 0x10 + + lw ta0, 0x00(src) + lw ta1, 0x04(src) + dsubu a1, a1, 0x8 + ADDC(sum, ta0) + ADDC(sum, ta1) + daddu src, src, 0x8 + andi t8, src, 0x10 + +oword_align: + beqz t8, begin_movement + dsrl t8, a1, 0x7 + + lw ta3, 0x08(src) + lw t0, 0x0c(src) + lw ta0, 0x00(src) + lw ta1, 0x04(src) + ADDC(sum, ta3) + ADDC(sum, t0) + ADDC(sum, ta0) + ADDC(sum, ta1) + dsubu a1, a1, 0x10 + daddu src, src, 0x10 + dsrl t8, a1, 0x7 + +begin_movement: + beqz t8, 1f + andi ta2, a1, 0x40 + +move_128bytes: + CSUM_BIGCHUNK(src, 0x00, sum, ta0, ta1, ta3, t0) + CSUM_BIGCHUNK(src, 0x20, sum, ta0, ta1, ta3, t0) + CSUM_BIGCHUNK(src, 0x40, sum, ta0, ta1, ta3, t0) + CSUM_BIGCHUNK(src, 0x60, sum, ta0, ta1, ta3, t0) + dsubu t8, t8, 0x01 + bnez t8, move_128bytes + daddu src, src, 0x80 + +1: + beqz ta2, 1f + andi ta2, a1, 0x20 + +move_64bytes: + CSUM_BIGCHUNK(src, 0x00, sum, ta0, ta1, ta3, t0) + CSUM_BIGCHUNK(src, 0x20, sum, ta0, ta1, ta3, t0) + daddu src, src, 0x40 + +1: + beqz ta2, do_end_words + andi t8, a1, 0x1c + +move_32bytes: + CSUM_BIGCHUNK(src, 0x00, sum, ta0, ta1, ta3, t0) + andi t8, a1, 0x1c + daddu src, src, 0x20 + +do_end_words: + beqz t8, maybe_end_cruft + dsrl t8, t8, 0x2 + +end_words: + lw ta0, (src) + dsubu t8, t8, 0x1 + ADDC(sum, ta0) + bnez t8, end_words + daddu src, src, 0x4 + +maybe_end_cruft: + andi ta2, a1, 0x3 + +small_memcpy: + j small_csumcpy; move a1, ta2 /* XXX ??? */ + beqz t2, out + move a1, ta2 + +end_bytes: + lb ta0, (src) + dsubu a1, a1, 0x1 + bnez a2, end_bytes + daddu src, src, 0x1 + +out: + jr ra + move v0, sum + END(csum_partial) diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/csum_partial_copy.c linux/arch/mips64/lib/csum_partial_copy.c --- v2.3.47/linux/arch/mips64/lib/csum_partial_copy.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/csum_partial_copy.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,50 @@ +/* $Id: csum_partial_copy.c,v 1.3 2000/02/05 06:47:09 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. + * + * MIPS64 specific IP/TCP/UDP checksumming routines + * + * Copyright (C) 1998, 1999 Ralf Baechle + */ +#include +#include +#include +#include +#include + +/* + * copy while checksumming, otherwise like csum_partial + */ +unsigned int csum_partial_copy(const char *src, char *dst, + int len, unsigned int sum) +{ + /* + * It's 2:30 am and I don't feel like doing it real ... + * This is lots slower than the real thing (tm) + */ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + + return sum; +} + +/* + * Copy from userspace and compute checksum. If we catch an exception + * then zero the rest of the buffer. + */ +unsigned int csum_partial_copy_from_user (const char *src, char *dst, + int len, unsigned int sum, + int *err_ptr) +{ + int missing; + + missing = copy_from_user(dst, src, len); + if (missing) { + memset(dst + len - missing, 0, missing); + *err_ptr = -EFAULT; + } + + return csum_partial(dst, len, sum); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/dump_tlb.c linux/arch/mips64/lib/dump_tlb.c --- v2.3.47/linux/arch/mips64/lib/dump_tlb.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/dump_tlb.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,207 @@ +/* + * Dump R4x00 TLB for debugging purposes. + * + * 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 + +#define mips_tlb_entries 64 + +void +dump_tlb(int first, int last) +{ + unsigned long s_entryhi, entryhi, entrylo0, entrylo1, asid; + unsigned int s_index, pagemask, c0, c1, i; + + s_entryhi = get_entryhi(); + s_index = get_index(); + asid = s_entryhi & 0xff; + + for (i = first; i <= last; i++) { + write_32bit_cp0_register(CP0_INDEX, i); + __asm__ __volatile__( + ".set\tnoreorder\n\t" + "nop;nop;nop;nop\n\t" + "tlbr\n\t" + "nop;nop;nop;nop\n\t" + ".set\treorder"); + pagemask = read_32bit_cp0_register(CP0_PAGEMASK); + entryhi = get_entryhi(); + entrylo0 = get_entrylo0(); + entrylo1 = get_entrylo1(); + + /* Unused entries have a virtual address of CKSEG0. */ + if ((entryhi & ~0x1ffffUL) != CKSEG0 + && (entryhi & 0xff) == asid) { + /* + * Only print entries in use + */ + printk("Index: %2d pgmask=%08x ", i, 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", + (entryhi & ~0x1fffUL), + entryhi & 0xff, + entrylo0 & PAGE_MASK, c0, + (entrylo0 & 4) ? 1 : 0, + (entrylo0 & 2) ? 1 : 0, + (entrylo0 & 1), + entrylo1 & PAGE_MASK, c1, + (entrylo1 & 4) ? 1 : 0, + (entrylo1 & 2) ? 1 : 0, + (entrylo1 & 1)); + + } + } + printk("\n"); + + set_entryhi(s_entryhi); + set_index(s_index); +} + +void +dump_tlb_all(void) +{ + dump_tlb(0, mips_tlb_entries - 1); +} + +void +dump_tlb_wired(void) +{ + int wired; + + wired = read_32bit_cp0_register(CP0_WIRED); + printk("Wired: %d", wired); + dump_tlb(0, read_32bit_cp0_register(CP0_WIRED)); +} + +#define BARRIER \ + __asm__ __volatile__( \ + ".set\tnoreorder\n\t" \ + "nop;nop;nop;nop;nop;nop;nop\n\t" \ + ".set\treorder"); + +void +dump_tlb_addr(unsigned long addr) +{ + unsigned int flags, oldpid; + int index; + + __save_and_cli(flags); + oldpid = get_entryhi() & 0xff; + BARRIER; + set_entryhi((addr & PAGE_MASK) | oldpid); + BARRIER; + tlb_probe(); + BARRIER; + index = get_index(); + set_entryhi(oldpid); + __restore_flags(flags); + + if (index < 0) { + printk("No entry for address 0x%08lx in TLB\n", addr); + return; + } + + printk("Entry %d maps address 0x%08lx\n", index, addr); + dump_tlb(index, index); +} + +void +dump_tlb_nonwired(void) +{ + dump_tlb(read_32bit_cp0_register(CP0_WIRED), mips_tlb_entries - 1); +} + +void +dump_list_process(struct task_struct *t, void *address) +{ + pgd_t *page_dir, *pgd; + pmd_t *pmd; + pte_t *pte, page; + unsigned int addr; + unsigned long val; + + 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("page_dir == %08x\n", (unsigned int) page_dir); + + pgd = pgd_offset(t->mm, addr); + printk("pgd == %08x, ", (unsigned int) pgd); + + pmd = pmd_offset(pgd, addr); + printk("pmd == %08x, ", (unsigned int) pmd); + + pte = pte_offset(pmd, addr); + printk("pte == %08x, ", (unsigned int) pte); + + page = *pte; + printk("page == %08x\n", (unsigned int) pte_val(page)); + + val = pte_val(page); + if (val & _PAGE_PRESENT) printk("present "); + if (val & _PAGE_READ) printk("read "); + if (val & _PAGE_WRITE) printk("write "); + if (val & _PAGE_ACCESSED) printk("accessed "); + if (val & _PAGE_MODIFIED) printk("modified "); + if (val & _PAGE_R4KBUG) printk("r4kbug "); + if (val & _PAGE_GLOBAL) printk("global "); + if (val & _PAGE_VALID) printk("valid "); + printk("\n"); +} + +void +dump_list_current(void *address) +{ + dump_list_process(current, address); +} + +unsigned int +vtop(void *address) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned int addr, paddr; + + addr = (unsigned long) address; + pgd = pgd_offset(current->mm, addr); + pmd = pmd_offset(pgd, addr); + pte = pte_offset(pmd, addr); + paddr = (KSEG1 | (unsigned int) pte_val(*pte)) & PAGE_MASK; + paddr |= (addr & ~PAGE_MASK); + + return paddr; +} + +void +dump16(unsigned long *p) +{ + int i; + + for(i=0;i<8;i++) + { + printk("*%08lx == %08lx, ", + (unsigned long)p, (unsigned long)*p++); + printk("*%08lx == %08lx\n", + (unsigned long)p, (unsigned long)*p++); + } +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/floppy-no.c linux/arch/mips64/lib/floppy-no.c --- v2.3.47/linux/arch/mips64/lib/floppy-no.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/floppy-no.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,58 @@ +/* $Id: floppy-no.c,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Dummy file for machines without standard floppy drives. + * + * Copyright (C) 1998 by Ralf Baechle + */ +#include +#include +#include +#include + +/* + * How to access the FDC's registers. + */ +static void no_fd_dummy(void) +{ + panic("no_fd_dummy called - shouldn't happen"); +} + +static unsigned long no_fd_getfdaddr1(void) +{ + return (unsigned long)-1; /* No FDC nowhere ... */ +} + +static unsigned long no_fd_drive_type(unsigned long n) +{ + return 0; +} + +struct fd_ops no_fd_ops = { + /* + * How to access the floppy controller's ports + */ + (void *) no_fd_dummy, + (void *) no_fd_dummy, + /* + * How to access the floppy DMA functions. + */ + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + no_fd_getfdaddr1, + (void *) no_fd_dummy, + (void *) no_fd_dummy, + no_fd_drive_type +}; diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/floppy-std.c linux/arch/mips64/lib/floppy-std.c --- v2.3.47/linux/arch/mips64/lib/floppy-std.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/floppy-std.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,166 @@ +/* $Id: floppy-std.c,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Access the floppy hardware on PC style hardware + * + * Copyright (C) 1996, 1997, 1998 by Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * How to access the FDC's registers. + */ +static unsigned char std_fd_inb(unsigned int port) +{ + return inb_p(port); +} + +static void std_fd_outb(unsigned char value, unsigned int port) +{ + outb_p(value, port); +} + +/* + * How to access the floppy DMA functions. + */ +static void std_fd_enable_dma(int channel) +{ + enable_dma(channel); +} + +static void std_fd_disable_dma(int channel) +{ + disable_dma(channel); +} + +static int std_fd_request_dma(int channel) +{ + return request_dma(channel, "floppy"); +} + +static void std_fd_free_dma(int channel) +{ + free_dma(channel); +} + +static void std_fd_clear_dma_ff(int channel) +{ + clear_dma_ff(channel); +} + +static void std_fd_set_dma_mode(int channel, char mode) +{ + set_dma_mode(channel, mode); +} + +static void std_fd_set_dma_addr(int channel, unsigned int addr) +{ + set_dma_addr(channel, addr); +} + +static void std_fd_set_dma_count(int channel, unsigned int count) +{ + set_dma_count(channel, count); +} + +static int std_fd_get_dma_residue(int channel) +{ + return get_dma_residue(channel); +} + +static void std_fd_enable_irq(int irq) +{ + enable_irq(irq); +} + +static void std_fd_disable_irq(int irq) +{ + disable_irq(irq); +} + +static unsigned long std_fd_getfdaddr1(void) +{ + 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); + unsigned long mem; + + mem = __get_dma_pages(GFP_KERNEL,order); + + return mem; +} + +static void std_fd_dma_mem_free(unsigned long addr, unsigned long size) +{ + free_pages(addr, __get_order(size)); +} + +static unsigned long std_fd_drive_type(unsigned long n) +{ + if (n == 0) + return 4; /* 3,5", 1.44mb */ + + return 0; +} + +struct fd_ops std_fd_ops = { + /* + * How to access the floppy controller's ports + */ + std_fd_inb, + std_fd_outb, + /* + * How to access the floppy DMA functions. + */ + std_fd_enable_dma, + std_fd_disable_dma, + std_fd_request_dma, + std_fd_free_dma, + std_fd_clear_dma_ff, + std_fd_set_dma_mode, + std_fd_set_dma_addr, + std_fd_set_dma_count, + std_fd_get_dma_residue, + std_fd_enable_irq, + std_fd_disable_irq, + std_fd_getfdaddr1, + std_fd_dma_mem_alloc, + std_fd_dma_mem_free, + std_fd_drive_type +}; diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/ide-no.c linux/arch/mips64/lib/ide-no.c --- v2.3.47/linux/arch/mips64/lib/ide-no.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/ide-no.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,71 @@ +/* $Id: ide-no.c,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Stub IDE routines to keep Linux from crashing on machine which don't + * have IDE like the Indy. + * + * Copyright (C) 1998, 1999 by Ralf Baechle + */ +#include +#include +#include +#include +#include + +static int no_ide_default_irq(ide_ioreg_t base) +{ + return 0; +} + +static ide_ioreg_t no_ide_default_io_base(int index) +{ + return 0; +} + +static void no_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, + ide_ioreg_t ctrl_port, int *irq) +{ +} + +static int no_ide_request_irq(unsigned int irq, + void (*handler)(int,void *, struct pt_regs *), + unsigned long flags, const char *device, + void *dev_id) +{ + panic("no_no_ide_request_irq called - shouldn't happen"); +} + +static void no_ide_free_irq(unsigned int irq, void *dev_id) +{ + panic("no_ide_free_irq called - shouldn't happen"); +} + +static int no_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + panic("no_ide_check_region called - shouldn't happen"); +} + +static void no_ide_request_region(ide_ioreg_t from, unsigned int extent, + const char *name) +{ + panic("no_ide_request_region called - shouldn't happen"); +} + +static void no_ide_release_region(ide_ioreg_t from, unsigned int extent) +{ + panic("no_ide_release_region called - shouldn't happen"); +} + +struct ide_ops no_ide_ops = { + &no_ide_default_irq, + &no_ide_default_io_base, + &no_ide_init_hwif_ports, + &no_ide_request_irq, + &no_ide_free_irq, + &no_ide_check_region, + &no_ide_request_region, + &no_ide_release_region +}; diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/ide-std.c linux/arch/mips64/lib/ide-std.c --- v2.3.47/linux/arch/mips64/lib/ide-std.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/ide-std.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,103 @@ +/* $Id: ide-std.c,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * IDE routines for typical pc-like standard configurations. + * + * Copyright (C) 1998, 1999 by Ralf Baechle + */ +#include +#include +#include +#include +#include +#include + +static int std_ide_default_irq(ide_ioreg_t base) +{ + switch (base) { + case 0x1f0: return 14; + case 0x170: return 15; + case 0x1e8: return 11; + case 0x168: return 10; + case 0x1e0: return 8; + case 0x160: return 12; + default: + return 0; + } +} + +static ide_ioreg_t std_ide_default_io_base(int index) +{ + switch (index) { + case 0: return 0x1f0; + case 1: return 0x170; + case 2: return 0x1e8; + case 3: return 0x168; + case 4: return 0x1e0; + case 5: return 0x160; + default: + return 0; + } +} + +static void std_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; +} + +static int std_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 std_ide_free_irq(unsigned int irq, void *dev_id) +{ + free_irq(irq, dev_id); +} + +static int std_ide_check_region(ide_ioreg_t from, unsigned int extent) +{ + return check_region(from, extent); +} + +static void std_ide_request_region(ide_ioreg_t from, unsigned int extent, + const char *name) +{ + request_region(from, extent, name); +} + +static void std_ide_release_region(ide_ioreg_t from, unsigned int extent) +{ + release_region(from, extent); +} + +struct ide_ops std_ide_ops = { + &std_ide_default_irq, + &std_ide_default_io_base, + &std_ide_init_hwif_ports, + &std_ide_request_irq, + &std_ide_free_irq, + &std_ide_check_region, + &std_ide_request_region, + &std_ide_release_region +}; diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/kbd-no.c linux/arch/mips64/lib/kbd-no.c --- v2.3.47/linux/arch/mips64/lib/kbd-no.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/kbd-no.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,63 @@ +/* $Id: kbd-no.c,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Stub keyboard and psaux routines to keep Linux from crashing on machines + * without a keyboard. + * + * Copyright (C) 1998 by Ralf Baechle + */ +#include +#include + +static void no_kbd_request_region(void) +{ + /* No I/O ports are being used on the Indy. */ +} + +static int no_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return -ENODEV; +} + +static int no_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return -ENODEV; +} + +static void no_aux_free_irq(void) +{ +} + +static unsigned char no_kbd_read_input(void) +{ + return 0; +} + +static void no_kbd_write_output(unsigned char val) +{ +} + +static void no_kbd_write_command(unsigned char val) +{ +} + +static unsigned char no_kbd_read_status(void) +{ + return 0; +} + +struct kbd_ops no_kbd_ops = { + no_kbd_request_region, + no_kbd_request_irq, + + no_aux_request_irq, + no_aux_free_irq, + + no_kbd_read_input, + no_kbd_write_output, + no_kbd_write_command, + no_kbd_read_status +}; diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/kbd-std.c linux/arch/mips64/lib/kbd-std.c --- v2.3.47/linux/arch/mips64/lib/kbd-std.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/kbd-std.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,81 @@ +/* $Id: kbd-std.c,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Routines for standard PC style keyboards accessible via I/O ports. + * + * Copyright (C) 1998, 1999 by Ralf Baechle + */ +#include +#include +#include +#include +#include + +#define KEYBOARD_IRQ 1 +#define AUX_IRQ 12 + +static void std_kbd_request_region(void) +{ + request_region(0x60, 16, "keyboard"); +} + +static int std_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL); +} + +static int std_aux_request_irq(void (*handler)(int, void *, struct pt_regs *)) +{ + return request_irq(AUX_IRQ, handler, 0, "PS/2 Mouse", NULL); +} + +static void std_aux_free_irq(void) +{ + free_irq(AUX_IRQ, NULL); +} + +static unsigned char std_kbd_read_input(void) +{ + return inb(KBD_DATA_REG); +} + +static void std_kbd_write_output(unsigned char val) +{ + int status; + + do { + status = inb(KBD_CNTL_REG); + } while (status & KBD_STAT_IBF); + outb(val, KBD_DATA_REG); +} + +static void std_kbd_write_command(unsigned char val) +{ + int status; + + do { + status = inb(KBD_CNTL_REG); + } while (status & KBD_STAT_IBF); + outb(val, KBD_CNTL_REG); +} + +static unsigned char std_kbd_read_status(void) +{ + return inb(KBD_STATUS_REG); +} + +struct kbd_ops std_kbd_ops = { + std_kbd_request_region, + std_kbd_request_irq, + + std_aux_request_irq, + std_aux_free_irq, + + std_kbd_read_input, + std_kbd_write_output, + std_kbd_write_command, + std_kbd_read_status +}; diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/memcpy.S linux/arch/mips64/lib/memcpy.S --- v2.3.47/linux/arch/mips64/lib/memcpy.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/memcpy.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,708 @@ +/* $Id: memcpy.S,v 1.4 2000/01/27 01:05:24 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Unified implementation of memcpy, memmove and the __copy_user backend. + * + * Copyright (C) 1998, 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + * + * 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. + */ +#include +#include +#include + +/* + * 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. + */ +#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 + +#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; \ + .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) + + .text + .set noreorder + .set noat + + .align 5 +LEAF(xxmemcpy) /* a0=dst a1=src a2=len */ + move v0, a0 /* return value */ +__memcpy: +FEXPORT(__copy_user) + xor ta0, a0, a1 + andi ta0, ta0, 0x3 + move t3, a0 + beqz ta0, can_align + sltiu t8, a2, 0x8 + + b memcpy_u_src # bad alignment + move ta2, a2 + +can_align: + bnez t8, small_memcpy # < 8 bytes to copy + move ta2, a2 + + beqz a2, out + andi t8, a1, 0x1 + +hword_align: + beqz t8, word_align + andi t8, a1, 0x2 + + EX(lb, ta0, (a1), l_fixup) + dsubu a2, a2, 0x1 + EX(sb, ta0, (a0), s_fixup) + daddu a1, a1, 0x1 + daddu a0, a0, 0x1 + andi t8, a1, 0x2 + +word_align: + beqz t8, dword_align + sltiu t8, a2, 56 + + EX(lh, ta0, (a1), l_fixup) + dsubu a2, a2, 0x2 + EX(sh, ta0, (a0), s_fixup) + sltiu t8, a2, 56 + daddu a0, a0, 0x2 + daddu 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, ta0, 0x00(a1), l_fixup) + dsubu a2, a2, 0x4 + EX(sw, ta0, 0x00(a0), s_fixup) + daddu a1, a1, 0x4 + daddu a0, a0, 0x4 + andi t8, a1, 0x8 + +qword_align: + beqz t8, oword_align + andi t8, a1, 0x10 + + EX(lw, ta0, 0x00(a1), l_fixup) + EX(lw, ta1, 0x04(a1), l_fixup) + dsubu a2, a2, 0x8 + EX(sw, ta0, 0x00(a0), s_fixup) + EX(sw, ta1, 0x04(a0), s_fixup) + daddu a1, a1, 0x8 + andi t8, a1, 0x10 + daddu a0, a0, 0x8 + +oword_align: + beqz t8, begin_movement + srl t8, a2, 0x7 + + EX(lw, ta3, 0x00(a1), l_fixup) + EX(lw, t0, 0x04(a1), l_fixup) + EX(lw, ta0, 0x08(a1), l_fixup) + EX(lw, ta1, 0x0c(a1), l_fixup) + EX(sw, ta3, 0x00(a0), s_fixup) + EX(sw, t0, 0x04(a0), s_fixup) + EX(sw, ta0, 0x08(a0), s_fixup) + EX(sw, ta1, 0x0c(a0), s_fixup) + dsubu a2, a2, 0x10 + daddu a1, a1, 0x10 + srl t8, a2, 0x7 + daddu a0, a0, 0x10 + +begin_movement: + beqz t8, 0f + andi ta2, a2, 0x40 + +move_128bytes: + MOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) + MOVE_BIGCHUNK(a1, a0, 0x20, ta0, ta1, ta3, t0) + MOVE_BIGCHUNK(a1, a0, 0x40, ta0, ta1, ta3, t0) + MOVE_BIGCHUNK(a1, a0, 0x60, ta0, ta1, ta3, t0) + dsubu t8, t8, 0x01 + daddu a1, a1, 0x80 + bnez t8, move_128bytes + daddu a0, a0, 0x80 + +0: + beqz ta2, 1f + andi ta2, a2, 0x20 + +move_64bytes: + MOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) + MOVE_BIGCHUNK(a1, a0, 0x20, ta0, ta1, ta3, t0) + daddu a1, a1, 0x40 + daddu a0, a0, 0x40 + +1: + beqz ta2, do_end_words + andi t8, a2, 0x1c + +move_32bytes: + MOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) + andi t8, a2, 0x1c + daddu a1, a1, 0x20 + daddu a0, a0, 0x20 + +do_end_words: + beqz t8, maybe_end_cruft + srl t8, t8, 0x2 + +end_words: + EX(lw, ta0, (a1), l_fixup) + dsubu t8, t8, 0x1 + EX(sw, ta0, (a0), s_fixup) + daddu a1, a1, 0x4 + bnez t8, end_words + daddu a0, a0, 0x4 + +maybe_end_cruft: + andi ta2, a2, 0x3 + +small_memcpy: + beqz ta2, out + move a2, ta2 + +end_bytes: + EX(lb, ta0, (a1), l_fixup) + dsubu a2, a2, 0x1 + EX(sb, ta0, (a0), s_fixup) + daddu a1, a1, 0x1 + bnez a2, end_bytes + daddu a0, a0, 0x1 + +out: jr ra + move a2, zero + +/* ------------------------------------------------------------------------- */ + +/* Bad, bad. At least try to align the source */ + +memcpy_u_src: + bnez t8, small_memcpy # < 8 bytes? + move ta2, a2 + + daddiu ta0, a1, 7 # ta0: how much to align + ori ta0, 7 + xori ta0, 7 + dsubu ta0, a1 + + UEX(ulw, ta1, 0(a1), l_fixup) # dword alignment + UEX(ulw, ta2, 4(a1), l_fixup) + UEX(usw, ta1, 0(a0), s_fixup) + UEX(usw, ta2, 4(a0), s_fixup) + + daddu a1, ta0 # src + daddu a0, ta0 # dst + dsubu a2, ta0 # 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, ta0, 0x00(a1), l_fixup) + EX(lw, ta1, 0x04(a1), l_fixup) + dsubu a2, a2, 0x8 + UEX(usw, ta0, 0x00(a0), s_fixup) + UEX(usw, ta1, 0x04(a0), s_fixup) + daddu a1, a1, 0x8 + andi t8, a1, 0x10 + daddu a0, a0, 0x8 + +u_oword_align: + beqz t8, u_begin_movement + srl t8, a2, 0x7 + + EX(lw, ta3, 0x08(a1), l_fixup) + EX(lw, t0, 0x0c(a1), l_fixup) + EX(lw, ta0, 0x00(a1), l_fixup) + EX(lw, ta1, 0x04(a1), l_fixup) + UEX(usw, ta3, 0x08(a0), s_fixup) + UEX(usw, t0, 0x0c(a0), s_fixup) + UEX(usw, ta0, 0x00(a0), s_fixup) + UEX(usw, ta1, 0x04(a0), s_fixup) + dsubu a2, a2, 0x10 + daddu a1, a1, 0x10 + srl t8, a2, 0x7 + daddu a0, a0, 0x10 + +u_begin_movement: + beqz t8, 0f + andi ta2, a2, 0x40 + +u_move_128bytes: + UMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) + UMOVE_BIGCHUNK(a1, a0, 0x20, ta0, ta1, ta3, t0) + UMOVE_BIGCHUNK(a1, a0, 0x40, ta0, ta1, ta3, t0) + UMOVE_BIGCHUNK(a1, a0, 0x60, ta0, ta1, ta3, t0) + dsubu t8, t8, 0x01 + daddu a1, a1, 0x80 + bnez t8, u_move_128bytes + daddu a0, a0, 0x80 + +0: + beqz ta2, 1f + andi ta2, a2, 0x20 + +u_move_64bytes: + UMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) + UMOVE_BIGCHUNK(a1, a0, 0x20, ta0, ta1, ta3, t0) + daddu a1, a1, 0x40 + daddu a0, a0, 0x40 + +1: + beqz ta2, u_do_end_words + andi t8, a2, 0x1c + +u_move_32bytes: + UMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) + andi t8, a2, 0x1c + daddu a1, a1, 0x20 + daddu a0, a0, 0x20 + +u_do_end_words: + beqz t8, u_maybe_end_cruft + srl t8, t8, 0x2 + +u_end_words: + EX(lw, ta0, 0x00(a1), l_fixup) + dsubu t8, t8, 0x1 + UEX(usw, ta0, 0x00(a0), s_fixup) + daddu a1, a1, 0x4 + bnez t8, u_end_words + daddu a0, a0, 0x4 + +u_maybe_end_cruft: + andi ta2, a2, 0x3 + +u_cannot_optimize: + beqz ta2, out + move a2, ta2 + +u_end_bytes: + EX(lb, ta0, (a1), l_fixup) + dsubu a2, a2, 0x1 + EX(sb, ta0, (a0), s_fixup) + daddu a1, a1, 0x1 + bnez a2, u_end_bytes + daddu a0, a0, 0x1 + + jr ra + move a2, zero + END(xxmemcpy) + +/* 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) + + .align 5 +LEAF(xxmemmove) + sltu ta0, a0, a1 # dst < src -> memcpy + bnez ta0, xxmemcpy + daddu v0, a0, a2 + sltu ta0, v0, a1 # dst + len < src -> non- + bnez ta0, __memcpy # overlapping, can use memcpy + move v0, a0 /* return value */ + END(xxmemmove) + +LEAF(__rmemcpy) /* a0=dst a1=src a2=len */ + daddu a0, a2 # dst = dst + len + daddu a1, a2 # src = src + len + +#if 0 /* Horror fix */ + xor ta0, a0, a1 + andi ta0, ta0, 0x3 + move t3, a0 + beqz ta0, r_can_align + sltiu t8, a2, 0x8 + + b r_memcpy_u_src # bad alignment + move ta2, a2 + +r_can_align: + bnez t8, r_small_memcpy # < 8 bytes to copy + move ta2, a2 + + beqz a2, r_out + andi t8, a1, 0x1 + +r_hword_align: + beqz t8, r_word_align + andi t8, a1, 0x2 + + lb ta0, -1(a1) + dsubu a2, a2, 0x1 + sb ta0, -1(a0) + dsubu a1, a1, 0x1 + dsubu a0, a0, 0x1 + andi t8, a1, 0x2 + +r_word_align: + beqz t8, r_dword_align + sltiu t8, a2, 56 + + lh ta0, -2(a1) + dsubu a2, a2, 0x2 + sh ta0, -2(a0) + sltiu t8, a2, 56 + dsubu a0, a0, 0x2 + dsubu 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 ta0, -4(a1) + dsubu a2, a2, 0x4 + sw ta0, -4(a0) + dsubu a1, a1, 0x4 + dsubu a0, a0, 0x4 + andi t8, a1, 0x8 + +r_qword_align: + beqz t8, r_oword_align + andi t8, a1, 0x10 + + dsubu a1, a1, 0x8 + lw ta0, 0x04(a1) + lw ta1, 0x00(a1) + dsubu a0, a0, 0x8 + sw ta0, 0x04(a0) + sw ta1, 0x00(a0) + dsubu a2, a2, 0x8 + + andi t8, a1, 0x10 + +r_oword_align: + beqz t8, r_begin_movement + srl t8, a2, 0x7 + + dsubu a1, a1, 0x10 + lw ta3, 0x08(a1) # assumes subblock ordering + lw t0, 0x0c(a1) + lw ta0, 0x00(a1) + lw ta1, 0x04(a1) + dsubu a0, a0, 0x10 + sw ta3, 0x08(a0) + sw t0, 0x0c(a0) + sw ta0, 0x00(a0) + sw ta1, 0x04(a0) + dsubu a2, a2, 0x10 + srl t8, a2, 0x7 + +r_begin_movement: + beqz t8, 0f + andi ta2, a2, 0x40 + +r_move_128bytes: + RMOVE_BIGCHUNK(a1, a0, -0x80, ta0, ta1, ta3, t0) + RMOVE_BIGCHUNK(a1, a0, -0x60, ta0, ta1, ta3, t0) + RMOVE_BIGCHUNK(a1, a0, -0x40, ta0, ta1, ta3, t0) + RMOVE_BIGCHUNK(a1, a0, -0x20, ta0, ta1, ta3, t0) + dsubu t8, t8, 0x01 + dsubu a1, a1, 0x80 + bnez t8, r_move_128bytes + dsubu a0, a0, 0x80 + +0: + beqz ta2, 1f + andi ta2, a2, 0x20 + +r_move_64bytes: + dsubu a1, a1, 0x40 + dsubu a0, a0, 0x40 + RMOVE_BIGCHUNK(a1, a0, 0x20, ta0, ta1, ta3, t0) + RMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) + +1: + beqz ta2, r_do_end_words + andi t8, a2, 0x1c + +r_move_32bytes: + dsubu a1, a1, 0x20 + dsubu a0, a0, 0x20 + RMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) + andi t8, a2, 0x1c + +r_do_end_words: + beqz t8, r_maybe_end_cruft + srl t8, t8, 0x2 + +r_end_words: + lw ta0, -4(a1) + dsubu t8, t8, 0x1 + sw ta0, -4(a0) + dsubu a1, a1, 0x4 + bnez t8, r_end_words + dsubu a0, a0, 0x4 + +r_maybe_end_cruft: + andi ta2, a2, 0x3 + +r_small_memcpy: + beqz ta2, r_out + move a2, ta2 +#endif /* Horror fix */ + +r_end_bytes: + lb ta0, -1(a1) + dsubu a2, a2, 0x1 + sb ta0, -1(a0) + dsubu a1, a1, 0x1 + bnez a2, r_end_bytes + dsubu a0, a0, 0x1 + +r_out: + 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 ta2, a2 + + andi ta0, a1, 7 # ta0: how much to align + + ulw ta1, -8(a1) # dword alignment + ulw ta2, -4(a1) + usw ta1, -8(a0) + usw ta2, -4(a0) + + dsubu a1, ta0 # src + dsubu a0, ta0 # dst + dsubu a2, ta0 # 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 + + dsubu a1, a1, 0x8 + lw ta0, 0x00(a1) + lw ta1, 0x04(a1) + dsubu a0, a0, 0x8 + usw ta0, 0x00(a0) + usw ta1, 0x04(a0) + dsubu a2, a2, 0x8 + + andi t8, a1, 0x10 + +ru_oword_align: + beqz t8, ru_begin_movement + srl t8, a2, 0x7 + + dsubu a1, a1, 0x10 + lw ta3, 0x08(a1) # assumes subblock ordering + lw t0, 0x0c(a1) + lw ta0, 0x00(a1) + lw ta1, 0x04(a1) + dsubu a0, a0, 0x10 + usw ta3, 0x08(a0) + usw t0, 0x0c(a0) + usw ta0, 0x00(a0) + usw ta1, 0x04(a0) + dsubu a2, a2, 0x10 + + srl t8, a2, 0x7 + +ru_begin_movement: + beqz t8, 0f + andi ta2, a2, 0x40 + +ru_move_128bytes: + RUMOVE_BIGCHUNK(a1, a0, -0x80, ta0, ta1, ta3, t0) + RUMOVE_BIGCHUNK(a1, a0, -0x60, ta0, ta1, ta3, t0) + RUMOVE_BIGCHUNK(a1, a0, -0x40, ta0, ta1, ta3, t0) + RUMOVE_BIGCHUNK(a1, a0, -0x20, ta0, ta1, ta3, t0) + dsubu t8, t8, 0x01 + dsubu a1, a1, 0x80 + bnez t8, ru_move_128bytes + dsubu a0, a0, 0x80 + +0: + beqz ta2, 1f + andi ta2, a2, 0x20 + +ru_move_64bytes: + dsubu a1, a1, 0x40 + dsubu a0, a0, 0x40 + RUMOVE_BIGCHUNK(a1, a0, 0x20, ta0, ta1, ta3, t0) + RUMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) + +1: + beqz ta2, ru_do_end_words + andi t8, a2, 0x1c + +ru_move_32bytes: + dsubu a1, a1, 0x20 + dsubu a0, a0, 0x20 + RUMOVE_BIGCHUNK(a1, a0, 0x00, ta0, ta1, ta3, t0) + andi t8, a2, 0x1c + +ru_do_end_words: + beqz t8, ru_maybe_end_cruft + srl t8, t8, 0x2 + +ru_end_words: + lw ta0, -4(a1) + usw ta0, -4(a0) + dsubu t8, t8, 0x1 + dsubu a1, a1, 0x4 + bnez t8, ru_end_words + dsubu a0, a0, 0x4 + +ru_maybe_end_cruft: + andi ta2, a2, 0x3 + +ru_cannot_optimize: + beqz ta2, r_out + move a2, ta2 + +ru_end_bytes: + lb ta0, -1(a1) + dsubu a2, a2, 0x1 + sb ta0, -1(a0) + dsubu a1, a1, 0x1 + bnez a2, ru_end_bytes + dsubu a0, a0, 0x1 + + jr ra + move a2, zero +#endif /* Horror fix */ + END(__rmemcpy) + +l_fixup: # clear the rest of the buffer + ld ta0, THREAD_BUADDR($28) + nop + dsubu a2, AT, ta0 # a2 bytes to go + daddu a0, ta0 # compute start address in a1 + dsubu a0, a1 + j __bzero + move a1, zero + +s_fixup: + jr ra + nop diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/memset.S linux/arch/mips64/lib/memset.S --- v2.3.47/linux/arch/mips64/lib/memset.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/memset.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,139 @@ +/* $Id: memset.S,v 1.3 2000/01/16 01:37:19 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1998, 1999 by Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include + +#define EX(insn,reg,addr,handler) \ +9: insn reg, addr; \ + .section __ex_table,"a"; \ + PTR 9b, handler; \ + .previous + +#define F_FILL64(dst, offset, val, fixup) \ + EX(sd, val, (offset + 0x00)(dst), fixup); \ + EX(sd, val, (offset + 0x08)(dst), fixup); \ + EX(sd, val, (offset + 0x10)(dst), fixup); \ + EX(sd, val, (offset + 0x18)(dst), fixup); \ + EX(sd, val, (offset + 0x20)(dst), fixup); \ + EX(sd, val, (offset + 0x28)(dst), fixup); \ + EX(sd, val, (offset + 0x30)(dst), fixup); \ + EX(sd, val, (offset + 0x38)(dst), fixup) + +/* + * memset(void *s, int c, size_t n) + * + * a0: start of area to clear + * a1: char to fill with + * a2: size of area to clear + */ +#include +#include + .set noreorder + .align 5 +LEAF(memset) + beqz a1, 1f + move v0, a0 /* result */ + + andi a1, 0xff /* spread fillword */ + dsll t1, a1, 8 + or a1, t1 + dsll t1, a1, 16 + or a1, t1 + dsll t1, a1, 32 + or a1, t1 + +1: + +FEXPORT(__bzero) + sltiu t0, a2, 8 /* very small region? */ + bnez t0, small_memset + andi t0, a0, 7 /* aligned? */ + + beqz t0, 1f + dsubu t0, 8 /* alignment in bytes */ + +#ifdef __MIPSEB__ + EX(sdl, a1, (a0), first_fixup) /* make dword aligned */ +#endif +#ifdef __MIPSEL__ + EX(sdr, a1, (a0), first_fixup) /* make dword aligned */ +#endif + dsubu a0, t0 /* dword align ptr */ + daddu a2, t0 /* correct size */ + +1: ori t1, a2, 0x3f /* # of full blocks */ + xori t1, 0x3f + beqz t1, memset_partial /* no block to fill */ + andi t0, a2, 0x38 + + daddu t1, a0 /* end address */ + .set reorder +1: daddiu a0, 64 + F_FILL64(a0, -64, a1, fwd_fixup) + bne t1, a0, 1b + .set noreorder + +memset_partial: + la t1, 2f /* where to start */ + .set noat + dsrl AT, t0, 1 + dsubu t1, AT + .set noat + jr t1 + daddu a0, t0 /* dest ptr */ + + F_FILL64(a0, -64, a1, partial_fixup) /* ... but first do dwds ... */ +2: andi a2, 7 /* 0 <= n <= 7 to go */ + + beqz a2, 1f + daddu a0, a2 /* What's left */ +#ifdef __MIPSEB__ + EX(sdr, a1, -1(a0), last_fixup) +#endif +#ifdef __MIPSEL__ + EX(sdl, a1, -1(a0), last_fixup) +#endif +1: jr ra + move a2, zero + +small_memset: + beqz a2, 2f + daddu t1, a0, a2 + +1: daddiu a0, 1 /* fill bytewise */ + bne t1, a0, 1b + sb a1, -1(a0) + +2: jr ra /* done */ + move a2, zero + END(memset) + +first_fixup: + jr ra + nop + +fwd_fixup: + ld t0, THREAD_BUADDR($28) + andi a2, 0x3f + daddu a2, t1 + jr ra + dsubu a2, t0 + +partial_fixup: + ld t0, THREAD_BUADDR($28) + andi a2, 7 + daddu a2, t1 + jr ra + dsubu a2, t0 + +last_fixup: + jr ra + andi v1, a2, 7 diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/rtc-no.c linux/arch/mips64/lib/rtc-no.c --- v2.3.47/linux/arch/mips64/lib/rtc-no.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/rtc-no.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,34 @@ +/* $Id: rtc-no.c,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Stub RTC routines to keep Linux from crashing on machine which don't + * have a RTC chip. + * + * Copyright (C) 1998 by Ralf Baechle + */ +#include +#include + +static unsigned char no_rtc_read_data(unsigned long addr) +{ + panic("no_rtc_read_data called - shouldn't happen."); +} + +static void no_rtc_write_data(unsigned char data, unsigned long addr) +{ + panic("no_rtc_write_data called - shouldn't happen."); +} + +static int no_rtc_bcd_mode(void) +{ + panic("no_rtc_bcd_mode called - shouldn't happen."); +} + +struct rtc_ops no_rtc_ops = { + &no_rtc_read_data, + &no_rtc_write_data, + &no_rtc_bcd_mode +}; diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/rtc-std.c linux/arch/mips64/lib/rtc-std.c --- v2.3.47/linux/arch/mips64/lib/rtc-std.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/rtc-std.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,35 @@ +/* $Id: rtc-std.c,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * RTC routines for PC style attached Dallas chip. + * + * Copyright (C) 1998 by Ralf Baechle + */ +#include +#include + +static unsigned char std_rtc_read_data(unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + return inb_p(RTC_PORT(1)); +} + +static void std_rtc_write_data(unsigned char data, unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + outb_p(data, RTC_PORT(1)); +} + +static int std_rtc_bcd_mode(void) +{ + return 1; +} + +struct rtc_ops std_rtc_ops = { + &std_rtc_read_data, + &std_rtc_write_data, + &std_rtc_bcd_mode +}; diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/strlen_user.S linux/arch/mips64/lib/strlen_user.S --- v2.3.47/linux/arch/mips64/lib/strlen_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/strlen_user.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,45 @@ +/* $Id: strlen_user.S,v 1.3 2000/01/17 23:32: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. + * + * Copyright (c) 1996, 1998, 1999 by Ralf Baechle + * Copyright (c) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include + +#define EX(insn,reg,addr,handler) \ +9: insn reg, addr; \ + .section __ex_table,"a"; \ + PTR 9b, handler; \ + .previous + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 for error + */ +LEAF(__strlen_user_asm) + ld v0, THREAD_CURDS($28) # pointer ok? + and v0, a0 + bltz v0, fault + +FEXPORT(__strlen_user_nocheck_asm) + move v0, a0 +1: EX(lb, ta0, (v0), fault) + daddiu v0, 1 + bnez ta0, 1b + dsubu v0, a0 + jr ra + END(__strlen_user_asm) + + .section __ex_table,"a" + PTR 1b, fault + .previous + +fault: move v0, zero + jr ra diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/strncpy_user.S linux/arch/mips64/lib/strncpy_user.S --- v2.3.47/linux/arch/mips64/lib/strncpy_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/strncpy_user.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,59 @@ +/* $Id: strncpy_user.S,v 1.3 2000/01/17 23:32: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. + * + * Copyright (c) 1996, 1999 by Ralf Baechle + */ +#include +#include +#include +#include + +#define EX(insn,reg,addr,handler) \ +9: insn reg, addr; \ + .section __ex_table,"a"; \ + PTR 9b, handler; \ + .previous + +/* + * Returns: -EFAULT if exception before terminator, N if the entire + * buffer filled, else strlen. + */ + +/* + * Ugly special case have to check: we might get passed a user space + * pointer which wraps into the kernel space. We don't deal with that. If + * it happens at most some bytes of the exceptions handlers will be copied. + */ + +LEAF(__strncpy_from_user_asm) + ld v0, THREAD_CURDS($28) # pointer ok? + and v0, a1 + bltz v0, fault + +FEXPORT(__strncpy_from_user_nocheck_asm) + move v0, zero + move v1, a1 + .set noreorder +1: EX(lbu, ta0, (v1), fault) + daddiu v1, 1 + beqz ta0, 2f + sb ta0, (a0) + daddiu v0, 1 + bne v0, a2, 1b + daddiu a0, 1 + .set reorder +2: daddu ta0, a1, v0 + xor ta0, a1 + bltz ta0, fault + jr ra # return n + END(__strncpy_from_user_asm) + +fault: li v0, -EFAULT + jr ra + + .section __ex_table,"a" + PTR 1b, fault + .previous diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/strnlen_user.S linux/arch/mips64/lib/strnlen_user.S --- v2.3.47/linux/arch/mips64/lib/strnlen_user.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/strnlen_user.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,47 @@ +/* $Id: strnlen_user.S,v 1.1 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1996, 1998, 1999 by Ralf Baechle + * Copyright (c) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include + +#define EX(insn,reg,addr,handler) \ +9: insn reg, addr; \ + .section __ex_table,"a"; \ + PTR 9b, handler; \ + .previous + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 for error, len on string but at max a1 otherwise + */ +LEAF(__strnlen_user_asm) + ld v0, THREAD_CURDS($28) # pointer ok? + and v0, ta0 + bltz v0, fault + +EXPORT(__strnlen_user_nocheck_asm) + move v0, a0 + daddu a1, a0 # stop pointer +1: beq v0, a1, 1f # limit reached? + EX(lb, ta0, (v0), fault) + daddiu v0, 1 + bnez ta0, 1b +1: dsubu v0, a0 + jr ra + END(__strnlen_user_asm) + + .section __ex_table,"a" + PTR 1b, fault + .previous + +fault: move v0, zero + jr ra diff -u --recursive --new-file v2.3.47/linux/arch/mips64/lib/watch.S linux/arch/mips64/lib/watch.S --- v2.3.47/linux/arch/mips64/lib/watch.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/lib/watch.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,61 @@ +/* $Id: watch.S,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Kernel debug stuff to use the Watch registers. + * Useful to find stack overflows, dangling pointers etc. + * + * Copyright (C) 1995, 1996, 1999 by Ralf Baechle + */ +#include +#include +#include + + .set noreorder +/* + * Parameter: a0 - logic address to watch + * Currently only KSEG0 addresses are allowed! + * a1 - set bit #1 to trap on load references + * bit #0 to trap on store references + * Results : none + */ + LEAF(__watch_set) + li t0,0x80000000 + subu a0,t0 + ori a0,7 + xori a0,7 + or a0,a1 + mtc0 a0,CP0_WATCHLO + sw a0,watch_savelo + + jr ra + mtc0 zero,CP0_WATCHHI + END(__watch_set) + +/* + * Parameter: none + * Results : none + */ + LEAF(__watch_clear) + jr ra + mtc0 zero,CP0_WATCHLO + END(__watch_clear) + +/* + * Parameter: none + * Results : none + */ + LEAF(__watch_reenable) + lw t0,watch_savelo + jr ra + mtc0 t0,CP0_WATCHLO + END(__watch_reenable) + +/* + * Saved value of the c0_watchlo register for watch_reenable() + */ + .data +watch_savelo: .word 0 + .text diff -u --recursive --new-file v2.3.47/linux/arch/mips64/mm/Makefile linux/arch/mips64/mm/Makefile --- v2.3.47/linux/arch/mips64/mm/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/mm/Makefile Thu Feb 24 22:53:35 2000 @@ -0,0 +1,33 @@ +# $Id: Makefile,v 1.5 2000/02/24 00:12:41 ralf Exp $ +# +# Makefile for the Linux/MIPS-specific parts of the memory manager. +# + +O_TARGET := mm.o +O_OBJS := extable.o init.o fault.o loadmmu.o + +ifdef CONFIG_CPU_R4300 +O_OBJS += r4xx0.o +endif +ifdef CONFIG_CPU_R4X00 +O_OBJS += r4xx0.o +endif +ifdef CONFIG_CPU_R5000 +O_OBJS += r4xx0.o +endif +ifdef CONFIG_CPU_NEVADA +O_OBJS += r4xx0.o +endif +ifdef CONFIG_CPU_R10000 +O_OBJS += andes.o +endif + +ifdef CONFIG_SGI_IP22 +O_OBJS += umap.o +endif + +ifdef CONFIG_BAGET_MIPS +O_OBJS += umap.o +endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/arch/mips64/mm/andes.c linux/arch/mips64/mm/andes.c --- v2.3.47/linux/arch/mips64/mm/andes.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/mm/andes.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,475 @@ +/* $Id: andes.c,v 1.6 2000/02/24 00:12:41 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1997, 1998, 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* CP0 hazard avoidance. I think we can drop this for the R10000. */ +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") + +/* R10000 has no Create_Dirty type cacheops. */ +static void andes_clear_page(void * page) +{ + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%2\n" + "1:\tsd\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\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, reg1, reg2; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%6\n" + "1:\tld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "ld\t%2,16(%1)\n\t" + "ld\t%3,24(%1)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%3,24(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "ld\t%2,-16(%1)\n\t" + "ld\t%3,-8(%1)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + " sd\t%3,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) + :"0" (to), "1" (from), "I" (PAGE_SIZE)); +} + +/* 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_all(void) +{ + blast_dcache32(); blast_icache64(); +} + +static void +andes_flush_cache_mm(struct mm_struct *mm) +{ + if (mm->context != 0) { +#ifdef DEBUG_CACHE + printk("cmm[%d]", (int)mm->context); +#endif + andes_flush_cache_all(); + } +} + +static void +andes_flush_cache_range(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_icache64(); + restore_flags(flags); + } +} + +static void +andes_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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->mm) && (pte_val(*ptep) & _PAGE_VALID)) { + blast_dcache32_page(page); + if(text) + blast_icache64_page(page); + } else { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (CKSEG0 + (page & (dcache_size - 1))); + blast_dcache32_page_indexed(page); + if(text) + blast_icache64_page_indexed(page); + } +out: + restore_flags(flags); +} + +/* Hoo hum... will this ever be called for an address that is not in CKSEG0 + and not cacheable? */ +static void +andes_flush_page_to_ram(struct page * page) +{ + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= K0BASE_NONCOH && addr < (0xb0UL << 56)) + || (addr >= KSEG0 && addr < KSEG1) + || (addr >= KSEG2)) { +#ifdef DEBUG_CACHE + printk("cram[%08lx]", addr); +#endif + blast_dcache32_page(addr); + } +} + +static void +andes_flush_cache_sigtramp(unsigned long addr) +{ + unsigned long daddr, iaddr; + + daddr = addr & ~(dc_lsize - 1); + protected_writeback_dcache_line(daddr); + protected_writeback_dcache_line(daddr + dc_lsize); + iaddr = addr & ~(ic_lsize - 1); + protected_flush_icache_line(iaddr); + protected_flush_icache_line(iaddr + ic_lsize); +} + +#define NTLB_ENTRIES 64 +#define NTLB_ENTRIES_HALF 32 + +/* TLB operations. + XXX These should work fine on R10k without the BARRIERs. */ +static inline void +andes_flush_tlb_all(void) +{ + unsigned long flags; + unsigned long old_ctx; + unsigned long 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(CKSEG0); + 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); +} + +static void andes_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->mm) + set_entryhi(mm->context & 0xff); + restore_flags(flags); + } +} + +static void +andes_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->mm) + set_entryhi(mm->context & 0xff); + } + __restore_flags(flags); + } +} + +static void +andes_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); + } +} + +/* XXX Simplify this. On the R10000 writing a TLB entry for an virtual + address that already exists will overwrite the old entry and not result + in TLB malfunction or TLB shutdown. */ +static void andes_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; + + 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); +} + +static int +andes_user_mode(struct pt_regs *regs) +{ + return (regs->cp0_status & ST0_KSU) == KSU_USER; +} + +static void andes_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\nbadvaddr: %016lx\n", + regs->cp0_epc, 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)); + + 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_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_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; + + update_mmu_cache = andes_update_mmu_cache; + + _show_regs = andes_show_regs; + _user_mode = andes_user_mode; + + 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); + + /* From this point on the ARC firmware is dead. */ + flush_tlb_all(); + + /* Did I tell you that ARC SUCKS? */ +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/mm/extable.c linux/arch/mips64/mm/extable.c --- v2.3.47/linux/arch/mips64/mm/extable.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/mm/extable.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,60 @@ +/* $Id: extable.c,v 1.2 1999/12/04 03:59:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994, 1995, 1996, 1999 by Ralf Baechle + * Copyright (C) 1999 by Silicon Graphics + */ +#include +#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->nextinsn; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return 0; +} + +unsigned long +search_exception_table(unsigned long addr) +{ + unsigned long ret; + +#ifndef CONFIG_MODULES + /* There is only the kernel to search. */ + ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); + if (ret) return ret; +#else + /* The kernel is the last "module" -- no need to treat it special. */ + struct module *mp; + for (mp = module_list; mp != NULL; mp = mp->next) { + if (mp->ex_table_start == NULL) + continue; + ret = search_one_table(mp->ex_table_start, + mp->ex_table_end - 1, addr); + if (ret) return ret; + } +#endif + + return 0; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/mm/fault.c linux/arch/mips64/mm/fault.c --- v2.3.47/linux/arch/mips64/mm/fault.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/mm/fault.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,184 @@ +/* $Id: fault.c,v 1.6 2000/02/18 00:24:31 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1995, 1996, 1997, 1998, 1999 by Ralf Baechle + * Copyright (C) 1999 by Silicon Graphics + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define development_version (LINUX_VERSION_CODE & 0x100) + +extern void die(char *, struct pt_regs *, unsigned long write); + +unsigned long asid_cache; + +/* + * Macro for exception fixup code to access integer registers. + */ +#define dpf_reg(r) (regs->regs[r]) + +/* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + */ +asmlinkage void +do_page_fault(struct pt_regs *regs, unsigned long write, unsigned long address) +{ + struct vm_area_struct * vma; + struct task_struct *tsk = current; + struct mm_struct *mm = tsk->mm; + int si_code = SEGV_MAPERR; + unsigned long fixup; + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || mm == &init_mm) + goto no_context; +#if 0 + printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid, + address, write, regs->cp0_epc); +#endif + down(&mm->mmap_sem); + vma = find_vma(mm, address); + if (!vma) + goto bad_area; + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (expand_stack(vma, address)) + goto bad_area; +/* + * Ok, we have a good vm_area for this memory access, so + * we can handle it.. + */ +good_area: + si_code = SEGV_ACCERR; + + if (write) { + if (!(vma->vm_flags & VM_WRITE)) + goto bad_area; + } else { + 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. + */ + { + int fault = handle_mm_fault(tsk, vma, address, write); + if (fault < 0) + goto out_of_memory; + if (!fault) + goto do_sigbus; + } + + up(&mm->mmap_sem); + return; + +/* + * Something tried to access memory that isn't in our memory map.. + * Fix it, but check if it's kernel or user first.. + */ +bad_area: + up(&mm->mmap_sem); + + if (user_mode(regs)) { + struct siginfo si; + tsk->thread.cp0_badvaddr = address; + tsk->thread.error_code = write; +#if 0 + printk("do_page_fault() #2: sending SIGSEGV to %s for illegal %s\n" + "%08lx (epc == %08lx, ra == %08lx)\n", + tsk->comm, + write ? "write access to" : "read access from", + address, + (unsigned long) regs->cp0_epc, + (unsigned long) regs->regs[31]); +#endif + si.si_signo = SIGSEGV; + si.si_code = si_code; + si.si_addr = (void *) address; + force_sig_info(SIGSEGV, &si, tsk); + return; + } + +no_context: + /* Are we prepared to handle this kernel fault? */ + fixup = search_exception_table(regs->cp0_epc); + if (fixup) { + long new_epc; + + tsk->thread.cp0_baduaddr = address; + new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc); + if (development_version) + printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n", + tsk->comm, regs->cp0_epc, new_epc); + regs->cp0_epc = new_epc; + return; + } + + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + printk(KERN_ALERT "Unable to handle kernel paging request at virtual " + "address %08lx, epc == %08lx, ra == %08lx\n", + address, regs->cp0_epc, regs->regs[31]); +while(1); + die("Oops", regs, write); + do_exit(SIGKILL); + +/* + * 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(&mm->mmap_sem); + printk("VM: killing process %s\n", tsk->comm); + if (user_mode(regs)) + do_exit(SIGKILL); + goto no_context; + +do_sigbus: + up(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + tsk->thread.cp0_badvaddr = address; + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + goto no_context; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/mm/init.c linux/arch/mips64/mm/init.c --- v2.3.47/linux/arch/mips64/mm/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/mm/init.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,448 @@ +/* $Id: init.c,v 1.13 2000/02/23 00:41:00 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994 - 2000 by Ralf Baechle + * Copyright (C) 1999, 2000 by Silicon Graphics + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_INITRD +#include +#endif + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SGI_IP22 +#include +#endif +#include + +unsigned long totalram_pages = 0; + +void __bad_pte_kernel(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd)); + pmd_set(pmd, BAD_PAGETABLE); +} + +void __bad_pte(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + pmd_set(pmd, BAD_PAGETABLE); +} + +/* Fixme, we need something like BAD_PMDTABLE ... */ +void __bad_pmd(pgd_t *pgd) +{ + printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); + pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); +} + +void pgd_init(unsigned long page) +{ + unsigned long *p, *end; + + p = (unsigned long *) page; + end = p + PTRS_PER_PGD; + + while (p < end) { + p[0] = (unsigned long) invalid_pmd_table; + p[1] = (unsigned long) invalid_pmd_table; + p[2] = (unsigned long) invalid_pmd_table; + p[3] = (unsigned long) invalid_pmd_table; + p[4] = (unsigned long) invalid_pmd_table; + p[5] = (unsigned long) invalid_pmd_table; + p[6] = (unsigned long) invalid_pmd_table; + p[7] = (unsigned long) invalid_pmd_table; + p += 8; + } +} + +pgd_t *get_pgd_slow(void) +{ + pgd_t *ret, *init; + + ret = (pgd_t *) __get_free_pages(GFP_KERNEL, 1); + if (ret) { + init = pgd_offset(&init_mm, 0); + pgd_init((unsigned long)ret); + } + return ret; +} + +void pmd_init(unsigned long addr) +{ + unsigned long *p, *end; + + p = (unsigned long *) addr; + end = p + PTRS_PER_PMD; + + while (p < end) { + p[0] = (unsigned long) invalid_pte_table; + p[1] = (unsigned long) invalid_pte_table; + p[2] = (unsigned long) invalid_pte_table; + p[3] = (unsigned long) invalid_pte_table; + p[4] = (unsigned long) invalid_pte_table; + p[5] = (unsigned long) invalid_pte_table; + p[6] = (unsigned long) invalid_pte_table; + p[7] = (unsigned long) invalid_pte_table; + p += 8; + } +} + +pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset) +{ + pmd_t *pmd; + + pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 1); + if (pgd_none(*pgd)) { + if (pmd) { + pmd_init((unsigned long)pmd); + pgd_set(pgd, pmd); + return pmd + offset; + } + pgd_set(pgd, BAD_PMDTABLE); + return NULL; + } + free_page((unsigned long)pmd); + if (pgd_bad(*pgd)) { + __bad_pmd(pgd); + return NULL; + } + return (pmd_t *) pgd_page(*pgd) + offset; +} + +pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *page; + + page = (pte_t *) __get_free_pages(GFP_USER, 1); + if (pmd_none(*pmd)) { + if (page) { + clear_page(page); + pmd_set(pmd, page); + return page + offset; + } + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + free_page((unsigned long)page); + if (pmd_bad(*pmd)) { + __bad_pte_kernel(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *page; + + page = (pte_t *) __get_free_pages(GFP_KERNEL, 1); + if (pmd_none(*pmd)) { + if (page) { + clear_page(page); + pmd_val(*pmd) = (unsigned long)page; + return page + offset; + } + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + free_pages((unsigned long)page, 1); + if (pmd_bad(*pmd)) { + __bad_pte(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +int do_check_pgt_cache(int low, int high) +{ + int freed = 0; + + if (pgtable_cache_size > high) { + do { + if (pgd_quicklist) + free_pgd_slow(get_pgd_fast()), freed++; + if (pmd_quicklist) + free_pmd_slow(get_pmd_fast()), freed++; + if (pte_quicklist) + free_pte_slow(get_pte_fast()), freed++; + } while (pgtable_cache_size > low); + } + return freed; +} + + +asmlinkage int sys_cacheflush(void *addr, int bytes, int cache) +{ + /* XXX Just get it working for now... */ + flush_cache_all(); + return 0; +} + +/* + * We have upto 8 empty zeroed pages so we can map one of the right colour + * when needed. This is necessary only on R4000 / R4400 SC and MC versions + * where we have to avoid VCED / VECI exceptions for good performance at + * any price. Since page is never written to after the initialization we + * don't have to care about aliases on other CPUs. + */ +unsigned long empty_zero_page, zero_page_mask; + +unsigned long setup_zero_pages(void) +{ + unsigned long order, size, pg; + + switch (mips_cputype) { + case CPU_R4000SC: + case CPU_R4000MC: + case CPU_R4400SC: + case CPU_R4400MC: + order = 3; + break; + default: + order = 0; + } + + empty_zero_page = __get_free_pages(GFP_KERNEL, order); + if (!empty_zero_page) + panic("Oh boy, that early out of memory?"); + + pg = MAP_NR(empty_zero_page); + while (pg < MAP_NR(empty_zero_page) + (1 << order)) { + set_bit(PG_reserved, &mem_map[pg].flags); + set_page_count(mem_map + pg, 0); + pg++; + } + + size = PAGE_SIZE << order; + zero_page_mask = (size - 1) & PAGE_MASK; + memset((void *)empty_zero_page, 0, size); + + return 1UL << order; +} + +extern inline void pte_init(unsigned long page) +{ + unsigned long *p, *end, bp; + + bp = pte_val(BAD_PAGE); + p = (unsigned long *) page; + end = p + PTRS_PER_PTE; + + while (p < end) { + p[0] = p[1] = p[2] = p[3] = + p[4] = p[5] = p[6] = p[7] = bp; + p += 8; + } +} + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving a inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +pmd_t * __bad_pmd_table(void) +{ + extern pmd_t invalid_pmd_table[PTRS_PER_PMD]; + unsigned long page; + + page = (unsigned long) invalid_pmd_table; + pte_init(page); + + return (pmd_t *) page; +} + +pte_t * __bad_pagetable(void) +{ + extern char empty_bad_page_table[PAGE_SIZE]; + unsigned long page; + + page = (unsigned long) empty_bad_page_table; + pte_init(page); + + return (pte_t *) page; +} + +pte_t __bad_page(void) +{ + extern char empty_bad_page[PAGE_SIZE]; + unsigned long page = (unsigned long) empty_bad_page; + + clear_page((void *)page); + return pte_mkdirty(mk_pte_phys(__pa(page), PAGE_SHARED)); +} + +void show_mem(void) +{ + int i, free = 0, total = 0, reserved = 0; + int shared = 0, cached = 0; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + i = max_mapnr; + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (PageSwapCache(mem_map+i)) + cached++; + else if (!page_count(mem_map + i)) + free++; + else + shared += page_count(mem_map + i) - 1; + } + printk("%d pages of RAM\n", total); + printk("%d reserved pages\n", reserved); + printk("%d pages shared\n", shared); + printk("%d pages swap cached\n",cached); + printk("%ld pages in page table cache\n", pgtable_cache_size); + printk("%d free pages\n", free); + show_buffers(); +} + +#ifndef CONFIG_DISCONTIGMEM +/* References to section boundaries */ + +extern char _ftext, _etext, _fdata, _edata; +extern char __init_begin, __init_end; + +void __init paging_init(void) +{ + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long max_dma, low; + + /* Initialize the entire pgd. */ + pgd_init((unsigned long)swapper_pg_dir); + pgd_init((unsigned long)swapper_pg_dir + PAGE_SIZE / 2); + pmd_init((unsigned long)invalid_pmd_table); + + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + low = max_low_pfn; + + if (low < max_dma) + zones_size[ZONE_DMA] = low; + else { + zones_size[ZONE_DMA] = max_dma; + zones_size[ZONE_NORMAL] = low - max_dma; + } + + free_area_init(zones_size); +} + +extern int page_is_ram(unsigned long pagenr); + +void __init mem_init(void) +{ + unsigned long codesize, reservedpages, datasize, initsize; + unsigned long tmp, ram; + + max_mapnr = num_physpages = max_low_pfn; + high_memory = (void *) __va(max_mapnr << PAGE_SHIFT); + + totalram_pages += free_all_bootmem(); + totalram_pages -= setup_zero_pages(); /* Setup zeroed pages. */ + + reservedpages = ram = 0; + for (tmp = 0; tmp < max_low_pfn; tmp++) + if (page_is_ram(tmp)) { + ram++; + if (PageReserved(mem_map+tmp)) + reservedpages++; + } + + 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", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + ram << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10); +} +#endif /* !CONFIG_DISCONTIGMEM */ + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + 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 - start) >> 10); +} +#endif + +extern char __init_begin, __init_end; +extern void prom_free_prom_memory(void); + +void +free_initmem(void) +{ + unsigned long addr, page; + + prom_free_prom_memory(); + + addr = (unsigned long)(&__init_begin); + while (addr < (unsigned long)&__init_end) { + page = PAGE_OFFSET | CPHYSADDR(addr); + ClearPageReserved(mem_map + MAP_NR(page)); + set_page_count(mem_map + MAP_NR(page), 1); + free_page(page); + totalram_pages++; + addr += PAGE_SIZE; + } + printk("Freeing unused kernel memory: %ldk freed\n", + (&__init_end - &__init_begin) >> 10); +} + +void +si_meminfo(struct sysinfo *val) +{ + val->totalram = totalram_pages; + val->sharedram = 0; + val->freeram = nr_free_pages(); + val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = 0; + val->freehigh = nr_free_highpages(); + val->mem_unit = PAGE_SIZE; + + return; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/mm/loadmmu.c linux/arch/mips64/mm/loadmmu.c --- v2.3.47/linux/arch/mips64/mm/loadmmu.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/mm/loadmmu.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,103 @@ +/* $Id: loadmmu.c,v 1.6 2000/02/24 00:12:41 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include + +#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_mm)(struct mm_struct *mm); +void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start, + unsigned long end); +void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page); +void (*_flush_cache_sigtramp)(unsigned long addr); +void (*_flush_page_to_ram)(struct page * page); + +/* 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); + +/* 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 *); + +int (*_user_mode)(struct pt_regs *); + +extern void ld_mmu_r4xx0(void); +extern void ld_mmu_andes(void); + +void __init load_mmu(void) +{ + switch(mips_cputype) { +#if defined (CONFIG_CPU_R4300) \ + || defined (CONFIG_CPU_R4X00) \ + || defined (CONFIG_CPU_R5000) \ + || defined (CONFIG_CPU_NEVADA) + case CPU_R4000PC: + case CPU_R4000SC: + case CPU_R4000MC: + case CPU_R4200: + case CPU_R4300: + case CPU_R4400PC: + case CPU_R4400SC: + case CPU_R4400MC: + case CPU_R4600: + case CPU_R4640: + case CPU_R4650: + case CPU_R4700: + case CPU_R5000: + case CPU_R5000A: + case CPU_NEVADA: + printk("Loading R4000 MMU routines.\n"); + ld_mmu_r4xx0(); + break; +#endif + +#if defined (CONFIG_CPU_R10000) + case CPU_R10000: + printk("Loading R10000 MMU routines.\n"); + ld_mmu_andes(); + break; +#endif + + default: + /* XXX We need an generic routine in the MIPS port + * XXX to jabber stuff onto the screen on all machines + * XXX before the console is setup. The ARCS prom + * XXX routines look good for this, but only the SGI + * XXX code has a full library for that at this time. + */ + panic("Yeee, unsupported mmu/cache architecture or " + "wrong compiletime kernel configuration."); + } +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/mm/r4xx0.c linux/arch/mips64/mm/r4xx0.c --- v2.3.47/linux/arch/mips64/mm/r4xx0.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/mm/r4xx0.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,2542 @@ +/* $Id: r4xx0.c,v 1.8 2000/02/24 00:12:41 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. + * + * r4xx0.c: R4000 processor variant specific MMU/Cache routines. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * Copyright (C) 1997, 1998, 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#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" + "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\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" + "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\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" + "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\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" + "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\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" + "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\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" + "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\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" + "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\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" + "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\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, reg1, reg2; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%6\n" + "1:\tcache\t%7,(%0)\n\t" + "ld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "cache\t%7,16(%0)\n\t" + "ld\t%2,16(%1)\n\t" + "ld\t%3,24(%1)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%3,24(%0)\n\t" + "cache\t%7,32(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "cache\t%7,-16(%0)\n\t" + "ld\t%2,-16(%1)\n\t" + "ld\t%3,-8(%1)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + " sd\t%4,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) + :"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, reg1, reg2; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%6\n" + "1:\tcache\t%7,(%0)\n\t" + "ld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "ld\t%2,16(%1)\n\t" + "ld\t%3,24(%1)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%3,24(%0)\n\t" + "cache\t%7,32(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "ld\t%2,-16(%1)\n\t" + "ld\t%3,-8(%1)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + " sd\t%3,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) + :"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, reg1, reg2; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%6\n" + "1:\tnop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "\tcache\t%7,(%0)\n\t" + "ld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "ld\t%2,16(%1)\n\t" + "ld\t%3,24(%1)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%3,24(%0)\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "cache\t%7,32(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "ld\t%2,-16(%1)\n\t" + "ld\t%3,-8(%1)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + " sd\t%3,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) + :"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, reg1, reg2; + unsigned int flags; + + __save_and_cli(flags); + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%6\n" + "1:\tnop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "\tcache\t%7,(%0)\n\t" + "ld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "ld\t%2,16(%1)\n\t" + "ld\t%3,24(%1)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%3,24(%0)\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "cache\t%7,32(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "ld\t%2,-16(%1)\n\t" + "ld\t%3,-8(%1)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + " sd\t%3,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) + :"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, reg1, reg2; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%6\n" + "1:\tcache\t%7,(%0)\n\t" + "ld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "cache\t%7,16(%0)\n\t" + "ld\t%2,16(%1)\n\t" + "ld\t%3,24(%1)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%3,24(%0)\n\t" + "cache\t%7,32(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "cache\t%7,-16(%0)\n\t" + "ld\t%2,-16(%1)\n\t" + "ld\t%3,-8(%1)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + " sd\t%3,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) + :"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, reg1, reg2; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%6\n" + "1:\tcache\t%7,(%0)\n\t" + "ld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "ld\t%2,16(%1)\n\t" + "ld\t%3,24(%1)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%3,24(%0)\n\t" + "cache\t%7,32(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "ld\t%2,-16(%1)\n\t" + "ld\t%3,-8(%1)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + " sd\t%3,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) + :"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, reg1, reg2; + + __asm__ __volatile__( + ".set\tnoreorder\n\t" + ".set\tnoat\n\t" + "daddiu\t$1,%0,%6\n" + "1:\tcache\t%7,(%0)\n\t" + "ld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "ld\t%2,16(%1)\n\t" + "ld\t%3,24(%1)\n\t" + "sd\t%2,16(%0)\n\t" + "sd\t%3,24(%0)\n\t" + "daddiu\t%0,64\n\t" + "daddiu\t%1,64\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "ld\t%2,-16(%1)\n\t" + "ld\t%3,-8(%1)\n\t" + "sd\t%2,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + " sd\t%3,-8(%0)\n\t" + ".set\tat\n\t" + ".set\treorder" + :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) + :"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" + "daddiu\t$1,%0,%8\n" + "1:\tcache\t%9,(%0)\n\t" + "ld\t%2,(%1)\n\t" + "ld\t%3,8(%1)\n\t" + "ld\t%4,16(%1)\n\t" + "ld\t%5,24(%1)\n\t" + "sd\t%2,(%0)\n\t" + "sd\t%3,8(%0)\n\t" + "sd\t%4,16(%0)\n\t" + "sd\t%5,24(%0)\n\t" + "ld\t%2,32(%1)\n\t" + "ld\t%3,40(%1)\n\t" + "ld\t%4,48(%1)\n\t" + "ld\t%5,56(%1)\n\t" + "sd\t%2,32(%0)\n\t" + "sd\t%3,40(%0)\n\t" + "sd\t%4,48(%0)\n\t" + "sd\t%5,56(%0)\n\t" + "daddiu\t%0,128\n\t" + "daddiu\t%1,128\n\t" + "ld\t%2,-64(%1)\n\t" + "ld\t%3,-56(%1)\n\t" + "ld\t%4,-48(%1)\n\t" + "ld\t%5,-40(%1)\n\t" + "sd\t%2,-64(%0)\n\t" + "sd\t%3,-56(%0)\n\t" + "sd\t%4,-48(%0)\n\t" + "sd\t%5,-40(%0)\n\t" + "ld\t%2,-32(%1)\n\t" + "ld\t%3,-24(%1)\n\t" + "ld\t%4,-16(%1)\n\t" + "ld\t%5,-8(%1)\n\t" + "sd\t%2,-32(%0)\n\t" + "sd\t%3,-24(%0)\n\t" + "sd\t%4,-16(%0)\n\t" + "bne\t$1,%0,1b\n\t" + " sd\t%5,-8(%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), + "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->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->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->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->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->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->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->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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->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); + if(text) + blast_icache16_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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->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); + if(text) + blast_icache16_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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->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); + if(text) + blast_icache16_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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->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); + if(text) + blast_icache16_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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->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); + if(text) + blast_icache32_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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->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); + if(text) + blast_icache32_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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->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); + if(text) + blast_icache32_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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->mm) { + blast_dcache16_page(page); + if(text) + blast_icache16_page(page); + } else { + /* Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache16_page_indexed(page); + if(text) + blast_icache16_page_indexed(page); + } +out: + restore_flags(flags); +} + +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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->mm) && (pte_val(*ptep) & _PAGE_VALID)) { + blast_dcache32_page(page); + if(text) + blast_icache32_page(page); + } else { + /* + * Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache32_page_indexed(page); + if(text) + blast_icache32_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; + int text; + + /* + * 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; + + text = (vma->vm_flags & VM_EXEC); + /* + * Doing flushes for another ASID than the current one is + * too difficult since stupid R4k caches do a TLB translation + * 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->mm) && (pte_val(*ptep) & _PAGE_VALID)) { + blast_dcache32_page(page); + if(text) + blast_icache32_page(page); + } else { + /* Do indexed flush, too much work to get the (possible) + * tlb refills to work correctly. + */ + page = (KSEG0 + (page & (dcache_size - 1))); + blast_dcache32_page_indexed(page); + blast_dcache32_page_indexed(page ^ dcache_waybit); + if(text) { + blast_icache32_page_indexed(page); + blast_icache32_page_indexed(page ^ icache_waybit); + } + } +out: + restore_flags(flags); +} + +/* 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_s16d16i16(struct page * page) +{ + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { +#ifdef DEBUG_CACHE + printk("cram[%08lx]", addr); +#endif + blast_scache16_page(addr); + } +} + +static void r4k_flush_page_to_ram_s32d16i16(struct page * page) +{ + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { +#ifdef DEBUG_CACHE + printk("cram[%08lx]", addr); +#endif + blast_scache32_page(addr); + } +} + +static void r4k_flush_page_to_ram_s64d16i16(struct page * page) +{ + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { +#ifdef DEBUG_CACHE + printk("cram[%08lx]", addr); +#endif + blast_scache64_page(addr); + } +} + +static void r4k_flush_page_to_ram_s128d16i16(struct page * page) +{ + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { +#ifdef DEBUG_CACHE + printk("cram[%08lx]", addr); +#endif + blast_scache128_page(addr); + } +} + +static void r4k_flush_page_to_ram_s32d32i32(struct page * page) +{ + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { +#ifdef DEBUG_CACHE + printk("cram[%08lx]", addr); +#endif + blast_scache32_page(addr); + } +} + +static void r4k_flush_page_to_ram_s64d32i32(struct page * page) +{ + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { +#ifdef DEBUG_CACHE + printk("cram[%08lx]", addr); +#endif + blast_scache64_page(addr); + } +} + +static void r4k_flush_page_to_ram_s128d32i32(struct page * page) +{ + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { +#ifdef DEBUG_CACHE + printk("cram[%08lx]", addr); +#endif + blast_scache128_page(addr); + } +} + +static void r4k_flush_page_to_ram_d16i16(struct page * page) +{ + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { + unsigned long flags; + +#ifdef DEBUG_CACHE + printk("cram[%08lx]", addr); +#endif + __save_and_cli(flags); + blast_dcache16_page(addr); + __restore_flags(flags); + } +} + +static void r4k_flush_page_to_ram_d32i32(struct page * page) +{ + unsigned long addr = page_address(page) & PAGE_MASK; + + if ((addr >= KSEG0 && addr < KSEG1) || (addr >= KSEG2)) { + unsigned long flags; + +#ifdef DEBUG_CACHE + printk("cram[%08lx]", addr); +#endif + __save_and_cli(flags); + blast_dcache32_page(addr); + __restore_flags(flags); + } +} + +/* + * 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) +{ + unsigned long daddr, iaddr; + + daddr = addr & ~(dc_lsize - 1); + __asm__ __volatile__("nop;nop;nop;nop"); /* R4600 V1.7 */ + protected_writeback_dcache_line(daddr); + protected_writeback_dcache_line(daddr + dc_lsize); + iaddr = addr & ~(ic_lsize - 1); + protected_flush_icache_line(iaddr); + protected_flush_icache_line(iaddr + ic_lsize); +} + +static void r4600v20k_flush_cache_sigtramp(unsigned long addr) +{ + unsigned long daddr, iaddr; + unsigned int flags; + + daddr = addr & ~(dc_lsize - 1); + __save_and_cli(flags); + + /* Clear internal cache refill buffer */ + *(volatile unsigned int *)KSEG1; + + protected_writeback_dcache_line(daddr); + protected_writeback_dcache_line(daddr + dc_lsize); + iaddr = addr & ~(ic_lsize - 1); + protected_flush_icache_line(iaddr); + protected_flush_icache_line(iaddr + ic_lsize); + __restore_flags(flags); +} + +#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... */ + +static inline void r4k_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 < NTLB_ENTRIES) { + set_index(entry); + BARRIER; + tlb_write_indexed(); + BARRIER; + entry++; + } + BARRIER; + set_entryhi(old_ctx); + restore_flags(flags); +} + +static void r4k_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->mm) + set_entryhi(mm->context & 0xff); + restore_flags(flags); + } +} + +static void r4k_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->mm) + set_entryhi(mm->context & 0xff); + } + __restore_flags(flags); + } +} + +static void r4k_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); + } +} + +#ifdef DEBUG_TLBUPDATE +static unsigned long ehi_debug[NTLB_ENTRIES]; +static unsigned long el0_debug[NTLB_ENTRIES]; +static unsigned long el1_debug[NTLB_ENTRIES]; +#endif + +/* We will need multiple versions of update_mmu_cache(), one that just + * updates the TLB with the new pte(s), and another which also checks + * for the R4k "end of page" hardware bug and does the needy. + */ +static void r4k_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; + + 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 + +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\nbadvaddr: %016lx\n", + regs->cp0_epc, regs->cp0_badvaddr); + printk("Status : %08x\nCause : %08x\n", + (unsigned int) regs->cp0_status, (unsigned int) regs->cp0_cause); +//{static int x = 3; x--; if(!x) while(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); +} + + +/* 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" + "cache 8, (%0)\n\t" + ".set reorder\n\t" : : "r" (begin)); + __asm__ __volatile__("\n\t.set noreorder\n\t" + "cache 9, (%0)\n\t" + ".set reorder\n\t" : : "r" (begin)); + __asm__ __volatile__("\n\t.set noreorder\n\t" + "cache 11, (%0)\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" + "cache 7, (%0)\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\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_d16i16; + 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; + } else if (prid == 0x2020) { /* R4600 V2.0 */ + _clear_page = r4k_clear_page_r4600_v2; + _copy_page = r4k_copy_page_r4600_v2; + } else { + _clear_page = r4k_clear_page_d32; + _copy_page = r4k_copy_page_d32; + } + _flush_cache_all = r4k_flush_cache_all_d32i32; + _flush_cache_mm = r4k_flush_cache_mm_d32i32; + _flush_cache_range = r4k_flush_cache_range_d32i32; + _flush_cache_page = r4k_flush_cache_page_d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_d32i32; + break; + } + _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; + _flush_page_to_ram = r4k_flush_page_to_ram_s16d16i16; + break; + case 32: + panic("Invalid cache configuration detected"); + }; + _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; + _flush_page_to_ram = r4k_flush_page_to_ram_s32d16i16; + break; + case 32: + _flush_cache_all = r4k_flush_cache_all_s32d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s32d32i32; + _flush_cache_range = r4k_flush_cache_range_s32d32i32; + _flush_cache_page = r4k_flush_cache_page_s32d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s32d32i32; + break; + }; + _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; + _flush_page_to_ram = r4k_flush_page_to_ram_s64d16i16; + break; + case 32: + _flush_cache_all = r4k_flush_cache_all_s64d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s64d32i32; + _flush_cache_range = r4k_flush_cache_range_s64d32i32; + _flush_cache_page = r4k_flush_cache_page_s64d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s64d32i32; + break; + }; + _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; + _flush_page_to_ram = r4k_flush_page_to_ram_s128d16i16; + break; + case 32: + _flush_cache_all = r4k_flush_cache_all_s128d32i32; + _flush_cache_mm = r4k_flush_cache_mm_s128d32i32; + _flush_cache_range = r4k_flush_cache_range_s128d32i32; + _flush_cache_page = r4k_flush_cache_page_s128d32i32; + _flush_page_to_ram = r4k_flush_page_to_ram_s128d32i32; + break; + }; + _clear_page = r4k_clear_page_s128; + _copy_page = r4k_copy_page_s128; + break; + } + _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(); +} + +static int r4k_user_mode(struct pt_regs *regs) +{ + return (regs->cp0_status & ST0_KSU) == KSU_USER; +} + +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)); + + set_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NONCOHERENT); + + probe_icache(config); + probe_dcache(config); + setup_scache(config); + + switch(mips_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; + if ((read_32bit_cp0_register(CP0_PRID) & 0xfff0) == 0x2020) { + _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; + + update_mmu_cache = r4k_update_mmu_cache; + + _show_regs = r4k_show_regs; + _user_mode = r4k_user_mode; + + flush_cache_all(); + write_32bit_cp0_register(CP0_WIRED, 0); + + /* + * You should never change this register: + * - On R4600 1.7 the tlbp never hits for pages smaller than + * the value in the c0_pagemask register. + * - The entire mm handling assumes the c0_pagemask register to + * be set for 4kb pages. + */ + write_32bit_cp0_register(CP0_PAGEMASK, PM_4K); + flush_tlb_all(); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/mm/umap.c linux/arch/mips64/mm/umap.c --- v2.3.47/linux/arch/mips64/mm/umap.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/mm/umap.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,211 @@ +/* $Id: umap.c,v 1.5 2000/02/04 07:40:24 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994 Linus Torvalds + * Copyright (C) 1997 Miguel de Icaza + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static inline void +remove_mapping_pte_range (pmd_t *pmd, unsigned long address, unsigned long size) +{ + pte_t *pte; + unsigned long end; + + if (pmd_none (*pmd)) + return; + if (pmd_bad (*pmd)){ + printk ("remove_graphics_pte_range: bad pmd (%08lx)\n", pmd_val (*pmd)); + pmd_clear (pmd); + return; + } + pte = pte_offset (pmd, address); + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t entry = *pte; + if (pte_present (entry)) + set_pte (pte, pte_modify (entry, PAGE_NONE)); + address += PAGE_SIZE; + pte++; + } while (address < end); + +} + +static inline void +remove_mapping_pmd_range (pgd_t *pgd, unsigned long address, unsigned long size) +{ + pmd_t *pmd; + unsigned long end; + + if (pgd_none (*pgd)) + return; + + if (pgd_bad (*pgd)){ + printk ("remove_graphics_pmd_range: bad pgd (%08lx)\n", pgd_val (*pgd)); + pgd_clear (pgd); + return; + } + pmd = pmd_offset (pgd, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + remove_mapping_pte_range (pmd, address, end - address); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + +} + +/* + * This routine is called from the page fault handler to remove a + * range of active mappings at this point + */ +void +remove_mapping (struct task_struct *task, unsigned long start, unsigned long end) +{ + unsigned long beg = start; + pgd_t *dir; + + down (&task->mm->mmap_sem); + dir = pgd_offset (task->mm, start); + flush_cache_range (task->mm, beg, end); + while (start < end){ + remove_mapping_pmd_range (dir, start, end - start); + start = (start + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + flush_tlb_range (task->mm, beg, end); + up (&task->mm->mmap_sem); +} + +void *vmalloc_uncached (unsigned long size) +{ + return vmalloc_prot (size, PAGE_KERNEL_UNCACHED); +} + +static inline void free_pte(pte_t page) +{ + if (pte_present(page)) { + unsigned long nr = pte_pagenr(page); + if (nr >= max_mapnr || PageReserved(mem_map+nr)) + return; + __free_page(pte_page(page)); + if (current->mm->rss <= 0) + return; + current->mm->rss--; + return; + } + swap_free(pte_to_swp_entry(page)); +} + +static inline void forget_pte(pte_t page) +{ + if (!pte_none(page)) { + printk("forget_pte: old mapping existed!\n"); + free_pte(page); + } +} + +/* + * maps a range of vmalloc()ed memory into the requested pages. the old + * mappings are removed. + */ +static inline void +vmap_pte_range (pte_t *pte, unsigned long address, unsigned long size, unsigned long vaddr) +{ + unsigned long end; + pgd_t *vdir; + pmd_t *vpmd; + pte_t *vpte; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t oldpage = *pte; + struct page * page; + pte_clear(pte); + + vdir = pgd_offset_k (vaddr); + vpmd = pmd_offset (vdir, vaddr); + vpte = pte_offset (vpmd, vaddr); + page = pte_page (*vpte); + + set_pte(pte, mk_pte(page, PAGE_USERIO)); + forget_pte(oldpage); + address += PAGE_SIZE; + vaddr += PAGE_SIZE; + pte++; + } while (address < end); +} + +static inline int +vmap_pmd_range (pmd_t *pmd, unsigned long address, unsigned long size, unsigned long vaddr) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + vaddr -= address; + do { + pte_t * pte = pte_alloc(pmd, address); + if (!pte) + return -ENOMEM; + vmap_pte_range(pte, address, end - address, address + vaddr); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +int +vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr) +{ + int error = 0; + pgd_t * dir; + unsigned long beg = from; + unsigned long end = from + size; + + vaddr -= from; + dir = pgd_offset(current->mm, from); + flush_cache_range(current->mm, beg, end); + while (from < end) { + pmd_t *pmd = pmd_alloc(dir, from); + error = -ENOMEM; + if (!pmd) + break; + error = vmap_pmd_range(pmd, from, end - from, vaddr + from); + if (error) + break; + from = (from + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + flush_tlb_range(current->mm, beg, end); + return error; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/Makefile linux/arch/mips64/sgi-ip22/Makefile --- v2.3.47/linux/arch/mips64/sgi-ip22/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/Makefile Thu Feb 24 22:53:35 2000 @@ -0,0 +1,16 @@ +# $Id: Makefile,v 1.4 2000/01/21 22:34:03 ralf Exp $ +# +# 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 +L_OBJS = 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 -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/ip22-berr.c linux/arch/mips64/sgi-ip22/ip22-berr.c --- v2.3.47/linux/arch/mips64/sgi-ip22/ip22-berr.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/ip22-berr.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,96 @@ +/* $Id: ip22-berr.c,v 1.2 2000/02/24 00:12:41 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle + * Copyright (C) 1999, 2000 by Silicon Graphics + */ +#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; +} + +static inline unsigned long +search_dbe_table(unsigned long addr) +{ + unsigned long ret; + + /* There is only the kernel to search. */ + ret = search_one_table(__start___dbe_table, __stop___dbe_table-1, addr); + if (ret) return ret; + + return 0; +} + +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 -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/ip22-hpc.c linux/arch/mips64/sgi-ip22/ip22-hpc.c --- v2.3.47/linux/arch/mips64/sgi-ip22/ip22-hpc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/ip22-hpc.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,103 @@ +/* $Id: ip22-hpc.c,v 1.2 1999/12/04 03:59:01 ralf Exp $ + * + * 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 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; + } else { +#ifdef DEBUG_SGIHPC + prom_printf("FULLHOUSE "); +#endif + 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 -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/ip22-int.c linux/arch/mips64/sgi-ip22/ip22-int.c --- v2.3.47/linux/arch/mips64/sgi-ip22/ip22-int.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/ip22-int.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,605 @@ +/* $Id: ip22-int.c,v 1.4 2000/02/04 07:40:24 ralf Exp $ + * + * indy_int.c: Routines for generic manipulation of the INT[23] ASIC + * found on INDY workstations.. + * + * 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 +#include + +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); +int (*irq_cannonicalize)(int irq); + +#ifdef CONFIG_REMOTE_DEBUG +extern void rs_kgdb_hook(int); +#endif + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; +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); + kstat.irqs[0][irq]++; + + printk("Got irq %d, press a key.", irq); + prom_getchar(); + ArcEnterInteractiveMode(); + + /* + * 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); + + /* 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); + kstat.irqs[0][irq + 16]++; + action->handler(irq, action->dev_id, regs); + irq_exit(cpu); +} + +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); + kstat.irqs[0][irq + 24]++; + action->handler(irq, action->dev_id, regs); + irq_exit(cpu); +} + +void indy_buserror_irq(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int irq = 6; + + irq_enter(cpu); + 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); +} + +/* 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 +} + +static int indy_irq_cannonicalize(int irq) +{ + return irq; /* Sane hardware, sane code ... */ +} + +void __init init_IRQ(void) +{ + irq_cannonicalize = indy_irq_cannonicalize; + sgint_init(); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/ip22-irq.S linux/arch/mips64/sgi-ip22/ip22-irq.S --- v2.3.47/linux/arch/mips64/sgi-ip22/ip22-irq.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/ip22-irq.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,129 @@ +/* $Id: ip22-irq.S,v 1.2 1999/12/04 03:59:01 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * 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 -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/ip22-mc.c linux/arch/mips64/sgi-ip22/ip22-mc.c --- v2.3.47/linux/arch/mips64/sgi-ip22/ip22-mc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/ip22-mc.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,161 @@ +/* $Id: ip22-mc.c,v 1.2 1999/12/04 03:59:01 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * indy_mc.c: Routines for manipulating the INDY memory controller. + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + */ +#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 = (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 -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/ip22-reset.c linux/arch/mips64/sgi-ip22/ip22-reset.c --- v2.3.47/linux/arch/mips64/sgi-ip22/ip22-reset.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/ip22-reset.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,241 @@ +/* $Id: ip22-reset.c,v 1.3 1999/12/04 03:59:01 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Reset an IP22. + * + * Copyright (C) 1997, 1998, 1999 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; + + del_timer(&blink_timer); + blink_timer.expires = jiffies + data; + add_timer(&blink_timer); +} + +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 -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/ip22-rtc.c linux/arch/mips64/sgi-ip22/ip22-rtc.c --- v2.3.47/linux/arch/mips64/sgi-ip22/ip22-rtc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/ip22-rtc.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,37 @@ +/* $Id: ip22-rtc.c,v 1.2 1999/12/04 03:59:01 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * RTC routines for Indy style attached Dallas chip. + * + * Copyright (C) 1998 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 -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/ip22-sc.c linux/arch/mips64/sgi-ip22/ip22-sc.c --- v2.3.47/linux/arch/mips64/sgi-ip22/ip22-sc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/ip22-sc.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,168 @@ +/* $Id: ip22-sc.c,v 1.2 1999/12/04 03:59:01 ralf Exp $ + * + * indy_sc.c: Indy cache managment 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 +#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_ROUND(n) ((n) + SC_LINE - 1) +#define SC_INDEX(n) ((n) & CI_MASK) + +static inline void indy_sc_wipe(unsigned long first, unsigned long last) +{ + __asm__ __volatile__(" + .set noreorder + or %0, %4 # first line to flush + or %1, %4 # last line to flush +1: sw $0, 0(%0) + bne %0, %1, 1b + daddu %0, 32 + .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 + /* Which lines to flush? */ + first_line = SC_INDEX(addr); + last_line = SC_INDEX(SC_ROUND(addr + size)); + + __save_and_cli(flags); + if (first_line <= last_line) { + indy_sc_wipe(first_line, last_line); + goto out; + } + + /* Cache index wrap around. Due to the way the buddy system works + this case should not happen. We're prepared to handle it, + though. */ + indy_sc_wipe(last_line, SC_SIZE); + indy_sc_wipe(0, first_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) +{ +return; /* Not for now, debugging ... */ + if (indy_sc_probe()) { + indy_sc_enable(); + bcops = &indy_sc_ops; + } +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/ip22-setup.c linux/arch/mips64/sgi-ip22/ip22-setup.c --- v2.3.47/linux/arch/mips64/sgi-ip22/ip22-setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/ip22-setup.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,188 @@ +/* $Id: ip22-setup.c,v 1.5 2000/01/27 01:05:24 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * 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 + +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 < MAP_NR(PAGE_OFFSET + 0x2000UL)) + return 1; + if (pagenr > MAP_NR(PAGE_OFFSET + 0x08002000)) + return 1; + return 0; +} + +void __init ip22_setup(void) +{ +#ifdef CONFIG_SERIAL_CONSOLE + char *ctype; +#endif + + /* 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 = ArcArcGetEnvironmentVariable("console"); + if(*ctype == 'd') { + if(*(ctype+1)=='2') + console_setup ("ttyS1"); + else + console_setup ("ttyS0"); + } +#endif +#ifdef CONFIG_SGI_PROM_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 -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/ip22-timer.c linux/arch/mips64/sgi-ip22/ip22-timer.c --- v2.3.47/linux/arch/mips64/sgi-ip22/ip22-timer.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/ip22-timer.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,295 @@ +/* $Id: ip22-timer.c,v 1.6 2000/02/04 07:40:24 ralf Exp $ + * + * 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 = 0; +unsigned long missed_heart_beats = 0; + +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; +} + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +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); + kstat.irqs[0][irq]++; + printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n"); + prom_getchar(); + ArcEnterInteractiveMode(); + irq_exit(cpu); +} + +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_state = TIME_BAD; + time_maxerror = MAXPHASE; + time_esterror = MAXPHASE; + write_unlock_irq(&xtime_lock); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/system.c linux/arch/mips64/sgi-ip22/system.c --- v2.3.47/linux/arch/mips64/sgi-ip22/system.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/system.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,135 @@ +/* $Id: system.c,v 1.3 1999/12/04 03:59:01 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * 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) +{ + 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(); + 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; + + + /* 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"); + prom_getchar(); + 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"); + prom_getchar(); + 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 -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip22/time.c linux/arch/mips64/sgi-ip22/time.c --- v2.3.47/linux/arch/mips64/sgi-ip22/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip22/time.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,20 @@ +/* $Id: time.c,v 1.2 1999/12/04 03:59:01 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * 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 -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/Makefile linux/arch/mips64/sgi-ip27/Makefile --- v2.3.47/linux/arch/mips64/sgi-ip27/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/Makefile Thu Feb 24 22:53:35 2000 @@ -0,0 +1,16 @@ +# $Id: Makefile,v 1.4 2000/02/18 00:24:31 ralf Exp $ +# +# Makefile for the IP27 specific kernel interface routines under Linux. +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +L_TARGET = ip27.a +L_OBJS = ip27-berr.o ip27-irq.o ip27-irq-glue.o ip27-klconfig.o \ + ip27-memory.o ip27-pci.o ip27-pci-dma.o ip27-reset.o ip27-setup.o \ + ip27-timer.o ip27-init.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/TODO linux/arch/mips64/sgi-ip27/TODO --- v2.3.47/linux/arch/mips64/sgi-ip27/TODO Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/TODO Thu Feb 24 22:53:35 2000 @@ -0,0 +1,11 @@ +1. Need to figure out why PCI writes to the IOC3 hang, and if it is okay +not to write to the IOC3 ever. +2. Need to figure out RRB allocation in bridge_startup(). +3. Need to figure out why address swaizzling is needed in inw/outw for +Qlogic scsi controllers. +4. Need to integrate ip27-klconfig.c:find_lboard and +ip27-init.c:find_lbaord_real. +5. Is it okay to set calias space on all nodes as 0, instead of 8k as +in irix? +6. Investigate why things do not work without the setup_test() call +being invoked on all nodes in ip27-memory.c. diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-berr.c linux/arch/mips64/sgi-ip27/ip27-berr.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-berr.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-berr.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,101 @@ +/* $Id: ip27-berr.c,v 1.1 2000/01/20 23:50:27 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle + * Copyright (C) 1999, 2000 by Silicon Graphics + */ +#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; +} + +static inline unsigned long +search_dbe_table(unsigned long addr) +{ + unsigned long ret; + + /* There is only the kernel to search. */ + ret = search_one_table(__start___dbe_table, __stop___dbe_table-1, addr); + if (ret) return ret; + + return 0; +} + +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) +{ + /* 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); + + LOCAL_HUB_S(PI_ERR_INT_PEND, + cpu ? PI_ERR_CLEAR_ALL_A : PI_ERR_CLEAR_ALL_B); + LOCAL_HUB_S(PI_ERR_INT_MASK_A + cpuoff, 0); + LOCAL_HUB_S(PI_ERR_STACK_ADDR_A + cpuoff, 0); + LOCAL_HUB_S(PI_ERR_STACK_SIZE, 0); /* Disable error stack */ + LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-init.c linux/arch/mips64/sgi-ip27/ip27-init.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-init.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,228 @@ +#include +#include /* for numnodes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned long cpumask_t; /* into asm/sn/types.h */ +typedef unsigned long cpuid_t; + +#define CPUMASK_CLRALL(p) (p) = 0 +#define CPUMASK_SETB(p, bit) (p) |= 1 << (bit) + +cpumask_t boot_cpumask; +hubreg_t region_mask = 0; +static int fine_mode = 0; + +cnodeid_t nasid_to_compact_node[MAX_NASIDS]; +nasid_t compact_to_nasid_node[MAX_COMPACT_NODES]; +cnodeid_t cpuid_to_compact_node[MAXCPUS]; + +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; +} + +static void gen_region_mask(hubreg_t *region_mask, int maxnodes) +{ + cnodeid_t cnode; + + (*region_mask) = 0; + for (cnode = 0; cnode < maxnodes; cnode++) { + (*region_mask) |= 1ULL << get_region(cnode); + } +} + +int is_fine_dirmode(void) +{ + return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK) + >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE); +} + +lboard_t * find_lboard_real(lboard_t *start, unsigned char brd_type) +{ + /* Search all boards stored on this node. */ + while (start) { + if (start->brd_type == brd_type) + return start; + start = KLCF_NEXT(start); + } + /* Didn't find it. */ + return (lboard_t *)NULL; +} + +klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type) +{ + int index, j; + + if (kli == (klinfo_t *)NULL) { + index = 0; + } else { + for (j = 0; j < KLCF_NUM_COMPS(brd); j++) + if (kli == KLCF_COMP(brd, j)) + break; + index = j; + if (index == KLCF_NUM_COMPS(brd)) { + printk("find_component: Bad pointer: 0x%p\n", kli); + return (klinfo_t *)NULL; + } + index++; /* next component */ + } + + for (; index < KLCF_NUM_COMPS(brd); index++) { + kli = KLCF_COMP(brd, index); + if (KLCF_COMP_TYPE(kli) == struct_type) + return kli; + } + + /* Didn't find it. */ + return (klinfo_t *)NULL; +} + +klinfo_t *find_first_component(lboard_t *brd, unsigned char struct_type) +{ + return find_component(brd, (klinfo_t *)NULL, struct_type); +} + +nasid_t get_actual_nasid(lboard_t *brd) +{ + klhub_t *hub; + + if (!brd) + return INVALID_NASID; + + /* find out if we are a completely disabled brd. */ + hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); + if (!hub) + return INVALID_NASID; + if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */ + return hub->hub_info.physid; + else + return brd->brd_nasid; +} + +int do_cpumask(cnodeid_t cnode, nasid_t nasid, cpumask_t *boot_cpumask, + int *highest) +{ + lboard_t *brd; + klcpu_t *acpu; + int cpus_found = 0; + cpuid_t cpuid; + + brd = find_lboard_real((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); + + do { + acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU); + while (acpu) { + cpuid = acpu->cpu_info.virtid; + /* cnode is not valid for completely disabled brds */ + if (get_actual_nasid(brd) == brd->brd_nasid) + cpuid_to_compact_node[cpuid] = cnode; + if (cpuid > *highest) + *highest = cpuid; + /* Only let it join in if it's marked enabled */ + if (acpu->cpu_info.flags & KLINFO_ENABLE) { + CPUMASK_SETB(*boot_cpumask, cpuid); + cpus_found++; + } + acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu, + KLSTRUCT_CPU); + } + brd = KLCF_NEXT(brd); + if (brd) + brd = find_lboard_real(brd,KLTYPE_IP27); + else + break; + } while (brd); + + return cpus_found; +} + +cpuid_t cpu_node_probe(cpumask_t *boot_cpumask, int *numnodes) +{ + int i, cpus = 0, highest = 0; + gda_t *gdap = GDA; + nasid_t nasid; + + /* + * Initialize the arrays to invalid nodeid (-1) + */ + for (i = 0; i < MAX_COMPACT_NODES; i++) + compact_to_nasid_node[i] = INVALID_NASID; + for (i = 0; i < MAX_NASIDS; i++) + nasid_to_compact_node[i] = INVALID_CNODEID; + for (i = 0; i < MAXCPUS; i++) + cpuid_to_compact_node[i] = INVALID_CNODEID; + + *numnodes = 0; + for (i = 0; i < MAX_COMPACT_NODES; i++) { + if ((nasid = gdap->g_nasidtable[i]) == INVALID_NASID) { + break; + } else { + compact_to_nasid_node[i] = nasid; + nasid_to_compact_node[nasid] = i; + (*numnodes)++; + cpus += do_cpumask(i, nasid, boot_cpumask, &highest); + } + } + + /* + * Cpus are numbered in order of cnodes. Currently, disabled + * cpus are not numbered. + */ + + return(highest + 1); +} + +void mlreset (void) +{ + int i, maxcpus; + + fine_mode = is_fine_dirmode(); + + /* + * Probe for all CPUs - this creates the cpumask and + * sets up the mapping tables. + */ + CPUMASK_CLRALL(boot_cpumask); + maxcpus = cpu_node_probe(&boot_cpumask, &numnodes); + + gen_region_mask(®ion_mask, numnodes); + + /* + * Set all nodes' calias sizes to 8k + */ + for (i = 0; i < numnodes; i++) { + nasid_t nasid; + + 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. + */ + REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1)); + REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0); + +#ifdef LATER + /* + * Set up all hubs to have a big window pointing at + * widget 0. Memory mode, widget 0, offset 0 + */ + REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN), + ((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) | + (0 << IIO_ITTE_WIDGET_SHIFT))); +#endif + } +} + diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-irq-glue.S linux/arch/mips64/sgi-ip27/ip27-irq-glue.S --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-irq-glue.S Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-irq-glue.S Thu Feb 24 22:53:35 2000 @@ -0,0 +1,65 @@ +/* $Id: ip27-irq-glue.S,v 1.1 2000/01/17 23:32:47 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include + + .text + .set noat + .align 5 +NESTED(ip27_irq, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + + /* IP27 may signal interrupt which we're not interested in. + Mask them out. */ + mfc0 s0, CP0_CAUSE + mfc0 t0, CP0_STATUS + and s0, t0 + + /* First check for RT interrupt. */ + andi a0, s0, CAUSEF_IP4 + beqz a0, 1f + + /* Ok, a timer interrupt. */ + move a0, sp + jal rt_timer_interrupt + + j ret_from_irq + +1: andi a0, s0, (CAUSEF_IP2 | CAUSEF_IP3) + beqz a0, 1f + + /* ... a device interrupt ... */ + move a0, sp + jal ip27_do_irq + + j ret_from_irq + +1: +#if 1 + mfc0 a1, CP0_STATUS + srl a1, a1, 8 + andi a1, 0xff + + mfc0 a2, CP0_CAUSE + srl a2, a2, 8 + andi a2, 0xff + + move a3, s0 + PRINT("Spurious interrupt, c0_status = %02x, c0_cause = %02x, pending %02x.\n") + ld a1, PT_EPC(sp) +0: b 0b +#endif + + j ret_from_irq + END(ip27_irq) diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-irq.c linux/arch/mips64/sgi-ip27/ip27-irq.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-irq.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,370 @@ +/* $Id: ip27-irq.c,v 1.6 2000/02/10 05:58:56 dagum Exp $ + * + * ip27-irq.c: Highlevel interrupt handling for IP27 architecture. + * + * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#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 asmlinkage void ip27_irq(void); +int (*irq_cannonicalize)(int irq); + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; +unsigned long spurious_count = 0; + +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 < 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"); + } + return len; +} + +/* + * do_IRQ handles all normal device IRQ's (the special SMP cross-CPU interrupts + * have their own specific handlers). + */ +asmlinkage void do_IRQ(int irq, struct pt_regs * regs) +{ + struct irqaction *action; + int do_random, cpu; + + cpu = smp_processor_id(); + irq_enter(cpu); + kstat.irqs[cpu][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); + + /* unmasking and bottom half handling is done magically for us. */ +} + +/* + * Find first bit set + */ +static 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); +} + +/* For now ... */ +void ip27_do_irq(struct pt_regs *regs) +{ + int irq; + hubreg_t pend0, mask0; + + /* copied from Irix intpend0() */ + while (((pend0 = LOCAL_HUB_L(PI_INT_PEND0)) & + (mask0 = LOCAL_HUB_L(PI_INT_MASK0_A))) != 0) { + do { + irq = ms1bit(pend0); + LOCAL_HUB_S(PI_INT_MASK0_A, mask0 & ~(1 << irq)); + LOCAL_HUB_S(PI_INT_PEND_MOD, irq); + LOCAL_HUB_L(PI_INT_MASK0_A); /* Flush */ + do_IRQ(irq, regs); + LOCAL_HUB_S(PI_INT_MASK0_A, mask0); + pend0 ^= 1ULL << irq; + } while (pend0); + } +} + + +/* Startup one of the (PCI ...) IRQs routes over a bridge. */ +static unsigned int bridge_startup(unsigned int irq) +{ + bridge_t *bridge = (bridge_t *) 0x9200000008000000; + bridgereg_t br; + int pin; + + /* FIIIIIXME ... Temporary kludge. This knows how interrupts are + setup in _my_ Origin. */ + switch (irq) { + case IOC3_SERIAL_INT: pin = 3; break; + case IOC3_ETH_INT: pin = 2; break; + case SCSI1_INT: pin = 1; break; + case SCSI0_INT: pin = 0; break; + default: panic("bridge_startup: whoops?"); + } + + br = LOCAL_HUB_L(PI_INT_MASK0_A); + LOCAL_HUB_S(PI_INT_MASK0_A, br | (1 << irq)); + LOCAL_HUB_L(PI_INT_MASK0_A); /* Flush */ + + bridge->b_int_addr[pin].addr = 0x20000 | irq; + bridge->b_int_enable |= (1 << pin); + if (irq < 2) { + bridgereg_t device; +#if 0 + /* + * Allocate enough RRBs on the bridge for the DMAs. + * Right now allocating 2 RRBs on the normal channel + * and 2 on the virtual channel for slot 0 on the bus. + * And same for slot 1, to get ioc3 eth working. + */ + Not touching b_even_resp /* boot doesn't go far */ + bridge->b_even_resp = 0xdd99cc88; /* boot doesn't go far */ + bridge->b_even_resp = 0xcccc8888; /* breaks eth0 */ + bridge->b_even_resp = 0xcc88; /* breaks eth0 */ +#endif + /* Turn on bridge swapping */ + device = bridge->b_device[irq].reg; + device |= BRIDGE_DEV_SWAP_DIR; + bridge->b_device[irq].reg = device; + } + bridge->b_widget.w_tflush; /* Flush */ + + return 0; /* Never anything pending. */ +} + +/* Startup one of the (PCI ...) IRQs routes over a bridge. */ +static unsigned int bridge_shutdown(unsigned int irq) +{ + bridge_t *bridge = (bridge_t *) 0x9200000008000000; + bridgereg_t br; + int pin; + + /* FIIIIIXME ... Temporary kludge. This knows how interrupts are + setup in _my_ Origin. */ + switch (irq) { + case IOC3_SERIAL_INT: pin = 3; break; + case IOC3_ETH_INT: pin = 2; break; + case SCSI1_INT: pin = 1; break; + case SCSI0_INT: pin = 0; break; + default: panic("bridge_startup: whoops?"); + } + + br = LOCAL_HUB_L(PI_INT_MASK0_A); + LOCAL_HUB_S(PI_INT_MASK0_A, br & ~(1 << irq)); + LOCAL_HUB_L(PI_INT_MASK0_A); /* Flush */ + + bridge->b_int_enable &= ~(1 << pin); + bridge->b_widget.w_tflush; /* Flush */ + + return 0; /* Never anything pending. */ +} + +static void bridge_init(void) +{ + bridge_t *bridge = (bridge_t *) 0x9200000008000000; + + /* Hmm... IRIX sets additional bits in the address which are + documented as reserved in the bridge docs ... */ + bridge->b_int_mode = 0x0; /* Don't clear ints */ +#if 0 + bridge->b_wid_int_upper = 0x000a8000; /* Ints to node 0 */ + bridge->b_wid_int_lower = 0x01000090; + bridge->b_dir_map = 0xa00000; /* DMA */ +#endif /* shouldn't lower= 0x01800090 ??? */ + bridge->b_wid_int_upper = 0x00098000; /* Ints to node 0 */ + bridge->b_wid_int_lower = 0x01800090; + bridge->b_dir_map = 0x900000; /* DMA */ + + bridge->b_int_enable = 0; + bridge->b_widget.w_tflush; /* Flush */ + set_cp0_status(SRB_DEV0 | SRB_DEV1, SRB_DEV0 | SRB_DEV1); +} + +void irq_debug(void) +{ + 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%x\n", LOCAL_HUB_L(PI_INT_PEND0)); + printk("PI_INT_MASK0_A = 0x%x\n", LOCAL_HUB_L(PI_INT_MASK0_A)); +} + +int setup_irq(int irq, struct irqaction *new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + 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) { + bridge_startup(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 > 9) + return -EINVAL; + 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; + + retval = setup_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 > 9) { + 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]) + bridge_shutdown(irq); + restore_flags(flags); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); +} + +/* Useless ISA nonsense. */ +unsigned long probe_irq_on (void) +{ + return 0; +} + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + +static int indy_irq_cannonicalize(int irq) +{ + return irq; /* Sane hardware, sane code ... */ +} + +void __init init_IRQ(void) +{ + irq_cannonicalize = indy_irq_cannonicalize; + + bridge_init(); + set_except_vector(0, ip27_irq); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-klconfig.c linux/arch/mips64/sgi-ip27/ip27-klconfig.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-klconfig.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-klconfig.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,33 @@ +/* $Id: ip27-klconfig.c,v 1.1 2000/01/17 23:32:47 ralf Exp $ + * + * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +lboard_t *find_lboard(unsigned int type) +{ + lboard_t *b; + + for ( +b = KL_CONFIG_INFO(get_nasid()); +b; +b = KLCF_NEXT(b)) { + if (KLCF_REMOTE(b)) + continue; /* Skip remote boards. */ + + if (b->brd_type == type) + return (lboard_t *) b; + } + + return NULL; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-memory.c linux/arch/mips64/sgi-ip27/ip27-memory.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-memory.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-memory.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,388 @@ +/* $Id: ip27-memory.c,v 1.9 2000/02/10 09:07:31 kanoj 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) 2000 by Ralf Baechle + * Copyright (C) 2000 by Silicon Graphics, Inc. + * + * On SGI IP27 the ARC memory configuration data is completly bogus but + * alternate easier to use mechanisms are available. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned long pfn_t; /* into */ +#define KDM_TO_PHYS(x) ((x) & TO_PHYS_MASK) /* into asm/addrspace.h */ + +extern char _end; + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define SLOT_IGNORED 0xffff + +short slot_lastfilled_cache[MAX_COMPACT_NODES]; +unsigned short slot_psize_cache[MAX_COMPACT_NODES][MAX_MEM_SLOTS]; +static pfn_t numpages; +static pfn_t pagenr = 0; + +plat_pg_data_t *plat_node_data[MAX_COMPACT_NODES]; +bootmem_data_t plat_node_bdata[MAX_COMPACT_NODES]; + +int numa_debug(void) +{ + printk("NUMA debug\n"); + *(int *)0 = 0; + return(0); +} + +/* + * Return pfn of first free page of memory on a node. PROM may allocate + * data structures on the first couple of pages of the first slot of each + * node. If this is the case, getfirstfree(node) > getslotstart(node, 0). + */ +pfn_t node_getfirstfree(cnodeid_t cnode) +{ +#ifdef LATER + nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); + + if (cnode == 0) + return KDM_TO_PHYS((unsigned long)(&_end)); + return KDM_TO_PHYS(SYMMON_STK_ADDR(nasid, 0)); +#endif + if (cnode == 0) + return (KDM_TO_PHYS(PAGE_ALIGN((unsigned long)(&_end)) - + (CKSEG0 - K0BASE)) >> PAGE_SHIFT); + return slot_getbasepfn(cnode, 0); +} + +/* + * Return the number of pages of memory provided by the given slot + * on the specified node. + */ +pfn_t slot_getsize(cnodeid_t node, int slot) +{ + return (pfn_t) slot_psize_cache[node][slot]; +} + +/* + * Return highest slot filled + */ +int node_getlastslot(cnodeid_t node) +{ + return (int) slot_lastfilled_cache[node]; +} + +/* + * Return the pfn of the last free page of memory on a node. + */ +pfn_t node_getmaxclick(cnodeid_t node) +{ + pfn_t slot_psize; + int slot; + + /* + * Start at the top slot. When we find a slot with memory in it, + * that's the winner. + */ + for (slot = (node_getnumslots(node) - 1); slot >= 0; slot--) { + if ((slot_psize = slot_getsize(node, slot))) { + if (slot_psize == SLOT_IGNORED) + continue; + /* Return the basepfn + the slot size, minus 1. */ + return slot_getbasepfn(node, slot) + slot_psize - 1; + } + } + + /* + * If there's no memory on the node, return 0. This is likely + * to cause problems. + */ + return (pfn_t)0; +} + +static pfn_t slot_psize_compute(cnodeid_t node, int slot) +{ + nasid_t nasid; + lboard_t *brd; + klmembnk_t *banks; + unsigned long size; + + nasid = COMPACT_TO_NASID_NODEID(node); + /* Find the node board */ + brd = find_lboard_real((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); + if (!brd) + return 0; + + /* Get the memory bank structure */ + banks = (klmembnk_t *)find_first_component(brd, KLSTRUCT_MEMBNK); + if (!banks) + return 0; + + /* Size in _Megabytes_ */ + size = (unsigned long)banks->membnk_bnksz[slot/4]; + + /* hack for 128 dimm banks */ + if (size <= 128) { + if (slot%4 == 0) { + size <<= 20; /* size in bytes */ + return(size >> PAGE_SHIFT); + } else { + return 0; + } + } else { + size /= 4; + size <<= 20; + return(size >> PAGE_SHIFT); + } +} + +pfn_t szmem(pfn_t fpage, pfn_t maxpmem) +{ + cnodeid_t node; + int slot, numslots; + pfn_t num_pages = 0, slot_psize; + pfn_t slot0sz = 0, nodebytes; /* Hack to detect problem configs */ + int ignore; + + for (node = 0; node < numnodes; node++) { + numslots = node_getnumslots(node); + ignore = nodebytes = 0; + for (slot = 0; slot < numslots; slot++) { + slot_psize = slot_psize_compute(node, slot); + if (slot == 0) slot0sz = slot_psize; + /* + * We need to refine the hack when we have replicated + * kernel text. + */ + nodebytes += SLOT_SIZE; + if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) > + (slot0sz << PAGE_SHIFT)) + ignore = 1; + if (ignore && slot_psize) { + printk("Ignoring slot %d onwards on node %d\n", + slot, node); + slot_psize_cache[node][slot] = SLOT_IGNORED; + slot = numslots; + continue; + } + num_pages += slot_psize; + slot_psize_cache[node][slot] = + (unsigned short) slot_psize; + if (slot_psize) + slot_lastfilled_cache[node] = slot; + } + } + if (maxpmem) + return((maxpmem > num_pages) ? num_pages : maxpmem); + else + return num_pages; +} + +/* + * HACK ALERT - Things do not work if this is not here. Maybe this is + * acting as a pseudocacheflush operation. The write pattern seems to + * be important, writing a 0 does not help. + */ +void setup_test(cnodeid_t node, pfn_t start, pfn_t end) +{ + unsigned long *ptr = __va(start << PAGE_SHIFT); + unsigned long size = 4 * 1024 * 1024; /* 4M L2 caches */ + + while (size) { + size -= sizeof(unsigned long); + *ptr = (0xdeadbeefbabeb000UL|node); + /* *ptr = 0; */ + ptr++; + } +} + +/* + * Currently, the intranode memory hole support assumes that each slot + * contains at least 32 MBytes of memory. We assume all bootmem data + * fits on the first slot. + */ +void __init prom_meminit(void) +{ + extern void mlreset(void); + cnodeid_t node; + pfn_t slot_firstpfn, slot_lastpfn, slot_freepfn; + unsigned long bootmap_size; + int node_datasz; + + node_datasz = PFN_UP(sizeof(plat_pg_data_t)); + mlreset(); + numpages = szmem(0, 0); + for (node = (numnodes - 1); node >= 0; node--) { + slot_firstpfn = slot_getbasepfn(node, 0); + slot_lastpfn = slot_firstpfn + slot_getsize(node, 0); + slot_freepfn = node_getfirstfree(node); + /* Foll line hack for non discontigmem; remove once discontigmem + * becomes the default. */ + max_low_pfn = (slot_lastpfn - slot_firstpfn); + if (node != 0) + setup_test(node, slot_freepfn, slot_lastpfn); + /* + * Allocate the node data structure on the node first. + */ + plat_node_data[node] = (plat_pg_data_t *)(__va(slot_freepfn \ + << PAGE_SHIFT)); + NODE_DATA(node)->bdata = plat_node_bdata + node; + slot_freepfn += node_datasz; + bootmap_size = init_bootmem_node(node, slot_freepfn, + slot_firstpfn, slot_lastpfn); + free_bootmem_node(node, slot_firstpfn << PAGE_SHIFT, + (slot_lastpfn - slot_firstpfn) << PAGE_SHIFT); + reserve_bootmem_node(node, slot_firstpfn << PAGE_SHIFT, + ((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size); + } + printk("Total memory probed : 0x%lx pages\n", numpages); +} + +int __init page_is_ram(unsigned long pagenr) +{ + return 1; +} + +void __init +prom_free_prom_memory (void) +{ + /* We got nothing to free here ... */ +} + +#ifdef CONFIG_DISCONTIGMEM + +void __init paging_init(void) +{ + cnodeid_t node; + unsigned int zones_size[MAX_NR_ZONES] = {0, 0, 0}; + + /* Initialize the entire pgd. */ + pgd_init((unsigned long)swapper_pg_dir); + pgd_init((unsigned long)swapper_pg_dir + PAGE_SIZE / 2); + pmd_init((unsigned long)invalid_pmd_table); + + for (node = 0; node < numnodes; node++) { + pfn_t start_pfn = slot_getbasepfn(node, 0); + pfn_t end_pfn = node_getmaxclick(node); + + zones_size[ZONE_DMA] = end_pfn + 1 - start_pfn; + PLAT_NODE_DATA(node)->physstart = (start_pfn << PAGE_SHIFT); + PLAT_NODE_DATA(node)->size = (zones_size[ZONE_DMA] << PAGE_SHIFT); + free_area_init_node(node, NODE_DATA(node), zones_size, + start_pfn << PAGE_SHIFT); + PLAT_NODE_DATA(node)->start_mapnr = + (NODE_DATA(node)->node_mem_map - mem_map); + if ((PLAT_NODE_DATA(node)->start_mapnr + + PLAT_NODE_DATA(node)->size) > pagenr) + pagenr = PLAT_NODE_DATA(node)->start_mapnr + + PLAT_NODE_DATA(node)->size; + } +} + +void __init mem_init(void) +{ + extern char _ftext, _etext, _fdata, _edata; + extern char __init_begin, __init_end; + extern unsigned long totalram_pages; + extern unsigned long setup_zero_pages(void); + cnodeid_t nid; + unsigned long tmp, ram; + unsigned long codesize, reservedpages, datasize, initsize; + int slot, numslots; + struct page *pg, *pslot; + pfn_t pgnr; + + num_physpages = numpages; /* memory already sized by szmem */ + max_mapnr = pagenr; /* already found during paging_init */ + high_memory = (void *) __va(max_mapnr << PAGE_SHIFT); + + for (nid = 0; nid < numnodes; nid++) { + + /* + * This will free up the bootmem, ie, slot 0 memory. + */ + totalram_pages += free_all_bootmem_node(nid); + + /* + * We need to manually do the other slots. + */ + pg = NODE_DATA(nid)->node_mem_map + slot_getsize(nid, 0); + pgnr = PLAT_NODE_DATA(nid)->start_mapnr + slot_getsize(nid, 0); + numslots = node_getlastslot(nid); + for (slot = 1; slot <= numslots; slot++) { + pslot = NODE_DATA(nid)->node_mem_map + + slot_getbasepfn(nid, slot) - slot_getbasepfn(nid, 0); + + /* + * Mark holes in previous slot. May also want to + * free up the pages that hold the memmap entries. + */ + while (pg < pslot) { + pg->flags |= (1<count, 1); + __free_page(pg); + totalram_pages++; + pg++; pgnr++; + } + } + } + + totalram_pages -= setup_zero_pages(); /* This comes from node 0 */ + + reservedpages = ram = 0; + for (nid = 0; nid < numnodes; nid++) { + for (tmp = PLAT_NODE_DATA(nid)->start_mapnr; tmp < + ((PLAT_NODE_DATA(nid)->start_mapnr) + + (PLAT_NODE_DATA(nid)->size >> PAGE_SHIFT)); tmp++) { + /* Ignore holes */ + if (PageSkip(mem_map+tmp)) + continue; + if (page_is_ram(tmp)) { + ram++; + if (PageReserved(mem_map+tmp)) + reservedpages++; + } + } + } + + 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", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + ram << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10); +} + +#endif /* CONFIG_DISCONTIGMEM */ diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-pci-dma.c linux/arch/mips64/sgi-ip27/ip27-pci-dma.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-pci-dma.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-pci-dma.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,55 @@ +/* $Id: ip27-pci-dma.c,v 1.1 2000/02/18 00:24:31 ralf Exp $ + * + * Dynamic DMA mapping support. + * + * On the Origin there is dynamic DMA address translation for all PCI DMA. + * However we don't use this facility yet but rely on the 2gb direct + * mapped DMA window for PCI64. So consistent alloc/free are merely page + * allocation/freeing. The rest of the dynamic DMA mapping interface is + * implemented in . So this code will fail with more than + * 2gb of memory. + */ +#include +#include +#include +#include +#include + +/* Pure 2^n version of get_order */ +extern __inline__ int __get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC; + int order = __get_order(size); + + if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + ret = (void *)__get_free_pages(gfp, order); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + + return ret; +} + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, __get_order(size)); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-pci.c linux/arch/mips64/sgi-ip27/ip27-pci.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-pci.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,258 @@ +/* $Id: ip27-pci.c,v 1.8 2000/02/16 01:07:30 ralf Exp $ + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include + +/* + * The Bridge ASIC supports both type 0 and type 1 access. Type 1 is + * not really documented, so right now I can't write code which uses it. + * Therefore we use type 0 accesses for now even though they won't work + * correcly for PCI-to-PCI bridges. + */ +#define CF0_READ_PCI_CFG(dev,where,value,bm,mask) \ +do { \ + bridge_t *bridge = (bridge_t *) 0x9200000008000000; \ + int slot = PCI_SLOT(dev->devfn); \ + int fn = PCI_FUNC(dev->devfn); \ + volatile u32 *addr; \ + u32 cf, __bit; \ + \ + if (dev->bus->number) \ + return PCIBIOS_DEVICE_NOT_FOUND; \ + \ + __bit = (((where) & (bm)) << 3); \ + addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; \ + if (get_dbe(cf, addr)) \ + return PCIBIOS_DEVICE_NOT_FOUND; \ + *value = (cf >> __bit) & (mask); \ + return PCIBIOS_SUCCESSFUL; \ +} while (0) + +static int +pci_conf0_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + CF0_READ_PCI_CFG(dev,where,value,3,0xff); +} + +static int +pci_conf0_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + CF0_READ_PCI_CFG(dev,where,value,2,0xffff); +} + +static int +pci_conf0_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + CF0_READ_PCI_CFG(dev,where,value,0,0xffffffff); +} + +#define CF0_WRITE_PCI_CFG(dev,where,value,bm,mask) \ +do { \ + bridge_t *bridge = (bridge_t *) 0x9200000008000000; \ + int slot = PCI_SLOT(dev->devfn); \ + int fn = PCI_FUNC(dev->devfn); \ + volatile u32 *addr; \ + u32 cf, __bit; \ + \ + if (dev->bus->number) \ + return PCIBIOS_DEVICE_NOT_FOUND; \ + \ + if (dev->vendor == PCI_VENDOR_ID_SGI \ + && dev->device == PCI_DEVICE_ID_SGI_IOC3) \ + return PCIBIOS_SUCCESSFUL; \ + \ + __bit = (((where) & (bm)) << 3); \ + addr = &bridge->b_type0_cfg_dev[slot].f[fn].l[where >> 2]; \ + if (get_dbe(cf, addr)) \ + return PCIBIOS_DEVICE_NOT_FOUND; \ + cf &= (~mask); \ + cf |= (value); \ + put_dbe(cf, addr); \ + return PCIBIOS_SUCCESSFUL; \ +} while (0) + +static int +pci_conf0_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + CF0_WRITE_PCI_CFG(dev,where,value,3,0xff); +} + +static int +pci_conf0_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + CF0_WRITE_PCI_CFG(dev,where,value,2,0xffff); +} + +static int +pci_conf0_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + CF0_WRITE_PCI_CFG(dev,where,value,0,0xffffffff); +} + + +static struct pci_ops bridge_pci_ops = { + pci_conf0_read_config_byte, + pci_conf0_read_config_word, + pci_conf0_read_config_dword, + pci_conf0_write_config_byte, + pci_conf0_write_config_word, + pci_conf0_write_config_dword +}; + +void __init pcibios_init(void) +{ + struct pci_ops *ops = &bridge_pci_ops; + nasid_t nid = get_nasid(); + + ioport_resource.end = ~0UL; + + printk("PCI: Probing PCI hardware on host bus 0, node %d.\n", nid); + pci_scan_bus(0, ops, NULL); +} + +static inline u8 +bridge_swizzle(u8 pin, u8 slot) +{ + return (((pin-1) + slot) % 4) + 1; +} + +static u8 __init +pci_swizzle(struct pci_dev *dev, u8 *pinp) +{ + u8 pin = *pinp; + + while (dev->bus->self) { /* Move up the chain of bridges. */ + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + dev = dev->bus->self; + } + *pinp = pin; + + return PCI_SLOT(dev->devfn); +} + +/* XXX This should include the node ID into the final interrupt number. */ +static int __init +pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + return (slot + (((pin-1) & 1) << 2)) & 7; +} + +void __init +pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + +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) +{ + unsigned short command; + struct list_head *ln; + struct pci_dev *dev; + + pci_fixup_irqs(pci_swizzle, pci_map_irq); + + /* + * Older qlogicisp driver expects to have the IO space enable + * bit set. Make that happen for qlogic in slots 0 and 1. Things + * stop working if we program the controllers as not having + * PCI_COMMAND_MEMORY, so we have to fudge the mem_flags. + */ + for (ln=b->devices.next; ln != &b->devices; ln=ln->next) { + dev = pci_dev_b(ln); + if (PCI_FUNC(dev->devfn) == 0) { + if ((PCI_SLOT(dev->devfn) == 0) || + (PCI_SLOT(dev->devfn) == 1)) { + if (pci_read_config_word(dev, PCI_COMMAND, + &command) == 0) { + command |= PCI_COMMAND_IO; + pci_write_config_word(dev, PCI_COMMAND, + command); + dev->resource[1].flags |= 1; + } + } + } + } +} + +void __init +pcibios_fixup_pbus_ranges(struct pci_bus * bus, + struct pbus_set_ranges_data * ranges) +{ + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; +} + +int __init +pcibios_enable_device(struct pci_dev *dev) +{ + /* Not needed, since we enable all devices at startup. */ + return 0; +} + +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; +} + +static void __init +pci_fixup_ioc3(struct pci_dev *d) +{ + int i; + + /* IOC3 only decodes 0x20 bytes of the config space, so we end up + with tons of bogus information in the pci_dev. On Origins the + INTA, INTB and INTC pins are all wired together as if it'd only + use INTA. */ + printk("PCI: Fixing base addresses for device %s\n", d->slot_name); + + for (i = 1; i <= PCI_ROM_RESOURCE; i++) { + d->resource[i].start = 0UL; + d->resource[i].end = 0UL; + d->resource[i].flags = 0UL; + } + d->subsystem_vendor = 0; + d->subsystem_device = 0; + d->irq = 1; +} + +struct pci_fixup pcibios_fixups[] = { + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, + pci_fixup_ioc3 }, + { 0 } +}; diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-reset.c linux/arch/mips64/sgi-ip27/ip27-reset.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-reset.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-reset.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,45 @@ +/* $Id: ip27-reset.c,v 1.1 2000/01/17 23:32:47 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. + * + * Reset an IP27. + * + * Copyright (C) 1997, 1998, 1999 by Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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) +{ + ArcReboot(); +} + +void machine_halt(void) +{ + ArcEnterInteractiveMode(); +} + +void machine_power_off(void) +{ + /* To do ... */ +} + +void ip27_reboot_setup(void) +{ + /* Nothing to do on IP27. */ +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-rtc.c linux/arch/mips64/sgi-ip27/ip27-rtc.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-rtc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-rtc.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,332 @@ +/* + * Driver for the SGS-Thomson M48T35 Timekeeper RAM chip + * + * Real Time Clock interface for Linux + * + * TODO: Implement periodic interrupts. + * + * Copyright (C) 2000 Silicon Graphics, Inc. + * Written by Ulf Carlsson (ulfc@engr.sgi.com) + * + * Based on code written by Paul Gortmaker. + * + * This driver allows use of the real time clock (built into + * nearly all computers) from user space. It exports the /dev/rtc + * interface supporting various ioctl() and also the /proc/rtc + * pseudo-file for status information. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the 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 RTC_VERSION "1.09b" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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); + +static void get_rtc_time(struct rtc_time *rtc_tm); + +/* + * Bits in rtc_status. (6 bits of room for future expansion) + */ + +#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ +#define RTC_TIMER_ON 0x02 /* missed irq timer active */ + +static unsigned char rtc_status = 0; /* bitmapped status byte. */ +static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ +static struct m48t35_rtc *rtc; + +/* + * 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 = 1970; /* year corresponding to 0x00 */ + +static const unsigned char days_in_mo[] = +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +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; + unsigned long flags; + + 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 + 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 -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + save_flags(flags); + cli(); + if (yrs > 169) { + restore_flags(flags); + 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); + + rtc->control &= ~M48T35_RTC_SET; + rtc->year = yrs; + rtc->month = mon; + rtc->date = day; + rtc->hour = hrs; + rtc->min = min; + rtc->sec = sec; + rtc->control &= ~M48T35_RTC_SET; + + restore_flags(flags); + return 0; + } + default: + return -EINVAL; + } + return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; +} + +/* + * We enforce only one user at a time here with the open/close. + * Also clear the previous interrupt data on an open, and clean + * up things on a close. + */ + +static int rtc_open(struct inode *inode, struct file *file) +{ + if(rtc_status & RTC_IS_OPEN) + return -EBUSY; + + MOD_INC_USE_COUNT; + + rtc_status |= RTC_IS_OPEN; + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + /* + * Turn off all interrupts once the device is no longer + * in use, and clear the data. + */ + + MOD_DEC_USE_COUNT; + + rtc_status &= ~RTC_IS_OPEN; + return 0; +} + +/* + * The various file operations we support. + */ + +static struct file_operations rtc_fops = { + NULL, /* No llseek (yet) */ + NULL, /* No read (yet) */ + NULL, /* No write */ + NULL, /* No readdir */ + NULL, /* No poll (yet) */ + rtc_ioctl, + NULL, /* No mmap */ + rtc_open, + NULL, /* flush */ + rtc_release +}; + +static struct miscdevice rtc_dev= +{ + RTC_MINOR, + "rtc", + &rtc_fops +}; + +static int __init rtc_init(void) +{ + unsigned long flags; + nasid_t nid; + + nid = get_nasid(); + rtc = (struct m48t35_rtc *) + 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); + create_proc_read_entry ("rtc", 0, NULL, rtc_read_proc, NULL); + + save_flags(flags); + cli(); + restore_flags(flags); + rtc_freq = 1024; + return 0; +} + +static void __exit rtc_exit (void) +{ + /* interrupts and timer disabled at this point by rtc_release */ + + remove_proc_entry ("rtc", NULL); + misc_deregister(&rtc_dev); +} + +module_init(rtc_init); +module_exit(rtc_exit); +EXPORT_NO_SYMBOLS; + +/* + * Info exported via "/proc/rtc". + */ + +static int rtc_get_status(char *buf) +{ + char *p; + struct rtc_time tm; + + /* + * Just emulate the standard /proc/rtc + */ + + 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" + "24hr\t\t: yes\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + + return p - buf; +} + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = rtc_get_status(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static void get_rtc_time(struct rtc_time *rtc_tm) +{ + + unsigned long flags; + + /* + * Do we need to wait for the last update to finish? + */ + + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Even though the + * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated + * by the RTC when initially set to a non-zero value. + */ + save_flags(flags); + cli(); + rtc->control |= M48T35_RTC_READ; + rtc_tm->tm_sec = rtc->sec; + rtc_tm->tm_min = rtc->min; + rtc_tm->tm_hour = rtc->hour; + rtc_tm->tm_mday = rtc->date; + rtc_tm->tm_mon = rtc->month; + rtc_tm->tm_year = rtc->year; + rtc->control &= ~M48T35_RTC_READ; + restore_flags(flags); + + BCD_TO_BIN(rtc_tm->tm_sec); + BCD_TO_BIN(rtc_tm->tm_min); + BCD_TO_BIN(rtc_tm->tm_hour); + BCD_TO_BIN(rtc_tm->tm_mday); + BCD_TO_BIN(rtc_tm->tm_mon); + BCD_TO_BIN(rtc_tm->tm_year); + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) + rtc_tm->tm_year += 100; + + rtc_tm->tm_mon--; +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-setup.c linux/arch/mips64/sgi-ip27/ip27-setup.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-setup.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,112 @@ +/* $Id: ip27-setup.c,v 1.6 2000/02/05 02:12:32 kanoj 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. + * + * SGI IP27 specific setup. + * + * Copyright (C) 1999 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999 Silcon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Check against user dumbness. */ +#ifdef CONFIG_VT +#error CONFIG_VT not allowed for IP27. +#endif + +/* + * get_nasid() returns the physical node id number of the caller. + */ +nasid_t +get_nasid(void) +{ + return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK) + >> NSRI_NODEID_SHFT); +} + +/* Extracted from the IOC3 meta driver. FIXME. */ +static inline void ioc3_sio_init(void) +{ + struct ioc3 *ioc3; + nasid_t nid; + long loops; + + nid = get_nasid(); + ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base; + + ioc3->sscr_a = 0; /* PIO mode for uarta. */ + ioc3->sscr_b = 0; /* PIO mode for uartb. */ + ioc3->sio_iec = ~0; + ioc3->sio_ies = (SIO_IR_SA_INT | SIO_IR_SB_INT); + + loops=1000000; while(loops--); + ioc3->sregs.uarta.iu_fcr = 0; + ioc3->sregs.uartb.iu_fcr = 0; + loops=1000000; while(loops--); +} + +static inline void ioc3_eth_init(void) +{ + struct ioc3 *ioc3; + nasid_t nid; + + nid = get_nasid(); + ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base; + + ioc3->eier = 0; +} + +/* Try to catch kernel missconfigurations and give user an indication what + option to select. */ +static void __init verify_mode(void) +{ + int n_mode; + + n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK; + printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M'); +#ifdef CONFIG_SGI_SN0_N_MODE + if (!n_mode) + panic("Kernel compiled for M mode."); +#else + if (n_mode) + panic("Kernel compiled for N mode."); +#endif +} + +void __init ip27_setup(void) +{ + nasid_t nid; + hubreg_t p, e; + + set_cp0_status(ST0_IM, 0); + nid = get_nasid(); + printk("IP27: Running on node %d.\n", nid); + + p = LOCAL_HUB_L(PI_CPU_PRESENT_A) & 1; + e = LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1; + printk("Node %d has %s primary CPU%s.\n", nid, + p ? "a" : "no", + e ? ", CPU is running" : ""); + + p = LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1; + e = LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1; + printk("Node %d has %s secondary CPU%s.\n", nid, + p ? "a" : "no", + e ? ", CPU is running" : ""); + + verify_mode(); + ioc3_sio_init(); + ioc3_eth_init(); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/sgi-ip27/ip27-timer.c linux/arch/mips64/sgi-ip27/ip27-timer.c --- v2.3.47/linux/arch/mips64/sgi-ip27/ip27-timer.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/sgi-ip27/ip27-timer.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,255 @@ +/* $Id: ip27-timer.c,v 1.3 2000/02/18 09:54:40 ulfc Exp $ + * + * Copytight (C) 1999 Ralf Baechle (ralf@gnu.org) + * Copytight (C) 1999 Silicon Graphics, Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* This is a hack; we really need to figure these values out dynamically + * + * Since 800 ns works very well with various HUB frequencies, such as + * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time. + * + * Ralf: which clock rate is used to feed the counter? + */ +#define NSEC_PER_CYCLE 800 +#define NSEC_PER_SEC 1000000000 +#define CYCLES_PER_SEC (NSEC_PER_SEC/NSEC_PER_CYCLE) +#define CYCLES_PER_JIFFY (CYCLES_PER_SEC/HZ) + +static unsigned long ct_cur; /* What counter should be at next timer irq */ +static long last_rtc_update = 0; /* Last time the rtc clock got updated */ + +extern rwlock_t xtime_lock; + + +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; + struct m48t35_rtc *rtc; + nasid_t nid; + + nid = get_nasid(); + rtc = (struct m48t35_rtc *) + KL_CONFIG_CH_CONS_INFO(nid)->memory_base + IOC3_BYTEBUS_DEV0; + + rtc->control |= M48T35_RTC_READ; + cmos_minutes = rtc->min; + BCD_TO_BIN(cmos_minutes); + rtc->control &= ~M48T35_RTC_READ; + + /* + * 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) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + rtc->control |= M48T35_RTC_SET; + rtc->sec = real_seconds; + rtc->min = real_minutes; + rtc->control &= ~M48T35_RTC_SET; + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + + return retval; +} + +void rt_timer_interrupt(struct pt_regs *regs) +{ + int irq = 7; /* XXX Assign number */ + + write_lock(&xtime_lock); + +again: + LOCAL_HUB_S(PI_RT_PEND_A, 0); /* Ack */ + ct_cur += CYCLES_PER_JIFFY; + LOCAL_HUB_S(PI_RT_COMPARE_A, ct_cur); + + if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur) + goto again; + + kstat.irqs[0][irq]++; + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to when a second starts. + */ + + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660) { + if (xtime.tv_usec >= 1000000 - ((unsigned) tick) / 2) { + if (set_rtc_mmss(xtime.tv_sec + 1) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; + } else if (xtime.tv_usec <= ((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; + } + } + + write_unlock(&xtime_lock); +} + +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_state = TIME_BAD; + time_maxerror = MAXPHASE; + time_esterror = MAXPHASE; + write_unlock_irq(&xtime_lock); +} + +/* Includes for ioc3_init(). */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +#define DEBUG_RTC + +static unsigned long __init get_m48t35_time(void) +{ + unsigned int year, month, date, hour, min, sec; + struct m48t35_rtc *rtc; + nasid_t nid; + + nid = get_nasid(); + rtc = KL_CONFIG_CH_CONS_INFO(nid)->memory_base + IOC3_BYTEBUS_DEV0; + + rtc->control |= M48T35_RTC_READ; + sec = rtc->sec; + min = rtc->min; + hour = rtc->hour; + date = rtc->date; + month = rtc->month; + year = rtc->year; + rtc->control &= ~M48T35_RTC_READ; + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(date); + BCD_TO_BIN(month); + BCD_TO_BIN(year); + + year += 1970; + + return mktime(year, month, date, hour, min, sec); +} + +extern void ioc3_eth_init(void); + +void __init time_init(void) +{ + lboard_t *board; + klcpu_t *cpu; + int cpuid; + + xtime.tv_sec = get_m48t35_time(); + xtime.tv_usec = 0; + + /* Don't use ARCS. ARCS is fragile. Klconfig is simple and sane. */ + board = find_lboard(KLTYPE_IP27); + if (!board) + panic("Can't find board info for myself."); + + cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX; + cpu = (klcpu_t *) KLCF_COMP(board, cpuid); + if (!cpu) + panic("No information about myself?"); + + printk("CPU clock is %dMHz.\n", cpu->cpu_speed); + + /* Don't worry about second CPU, it's disabled. */ + LOCAL_HUB_S(PI_RT_EN_A, 1); + LOCAL_HUB_S(PI_PROF_EN_A, 0); + ct_cur = CYCLES_PER_JIFFY; + LOCAL_HUB_S(PI_RT_COMPARE_A, ct_cur); + LOCAL_HUB_S(PI_RT_COUNT, 0); + LOCAL_HUB_S(PI_RT_PEND_A, 0); + + set_cp0_status(SRB_TIMOCLK, SRB_TIMOCLK); +} diff -u --recursive --new-file v2.3.47/linux/arch/mips64/tools/Makefile linux/arch/mips64/tools/Makefile --- v2.3.47/linux/arch/mips64/tools/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/tools/Makefile Thu Feb 24 22:53:35 2000 @@ -0,0 +1,29 @@ +# $Id: Makefile,v 1.2 1999/12/04 03:59:01 ralf Exp $ +# +# Makefile for MIPS kernel build tools. +# +# Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) +# Copyright (C) 1997, 1999 Ralf Baechle (ralf@gnu.org) +# Copyright (C) 1999 Silicon Graphics, Inc. +# +TARGET := $(TOPDIR)/include/asm-$(ARCH)/offset.h + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +all: $(TARGET) + +$(TARGET): offset.h + cmp -s $^ $@ || (cp $^ $(TARGET).new && mv $(TARGET).new $(TARGET)) + +offset.h: offset.s + sed -n '/^@@@/s///p' $^ >$@ + +offset.s: offset.c + +clean: + rm -f offset.[hs] $(TARGET).new + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/arch/mips64/tools/offset.c linux/arch/mips64/tools/offset.c --- v2.3.47/linux/arch/mips64/tools/offset.c Wed Dec 31 16:00:00 1969 +++ linux/arch/mips64/tools/offset.c Thu Feb 24 22:53:35 2000 @@ -0,0 +1,149 @@ +/* $Id: offset.c,v 1.4 1999/12/04 03:59:01 ralf Exp $ + * + * offset.c: Calculate pt_regs and task_struct offsets. + * + * Copyright (C) 1996 David S. Miller + * Copyright (C) 1997, 1998, 1999 Ralf Baechle + * Copyright (C) 1999 Silicon Graphics, Inc. + */ +#include +#include + +#include +#include + +#define text(t) __asm__("\n@@@" t) +#define _offset(type, member) (&(((type *)NULL)->member)) + +#define offset(string, ptr, member) \ + __asm__("\n@@@" string "%0" : : "i" (_offset(ptr, member))) +#define size(string, size) \ + __asm__("\n@@@" string "%0" : : "i" (sizeof(size))) +#define linefeed text("") + +text("/* DO NOT TOUCH, AUTOGENERATED BY OFFSET.C */"); +linefeed; +text("#ifndef _MIPS_OFFSET_H"); +text("#define _MIPS_OFFSET_H"); +linefeed; + +void output_ptreg_defines(void) +{ + text("/* MIPS pt_regs offsets. */"); + offset("#define PT_R0 ", struct pt_regs, regs[0]); + offset("#define PT_R1 ", struct pt_regs, regs[1]); + offset("#define PT_R2 ", struct pt_regs, regs[2]); + offset("#define PT_R3 ", struct pt_regs, regs[3]); + offset("#define PT_R4 ", struct pt_regs, regs[4]); + offset("#define PT_R5 ", struct pt_regs, regs[5]); + offset("#define PT_R6 ", struct pt_regs, regs[6]); + offset("#define PT_R7 ", struct pt_regs, regs[7]); + offset("#define PT_R8 ", struct pt_regs, regs[8]); + offset("#define PT_R9 ", struct pt_regs, regs[9]); + offset("#define PT_R10 ", struct pt_regs, regs[10]); + offset("#define PT_R11 ", struct pt_regs, regs[11]); + offset("#define PT_R12 ", struct pt_regs, regs[12]); + offset("#define PT_R13 ", struct pt_regs, regs[13]); + offset("#define PT_R14 ", struct pt_regs, regs[14]); + offset("#define PT_R15 ", struct pt_regs, regs[15]); + offset("#define PT_R16 ", struct pt_regs, regs[16]); + offset("#define PT_R17 ", struct pt_regs, regs[17]); + offset("#define PT_R18 ", struct pt_regs, regs[18]); + offset("#define PT_R19 ", struct pt_regs, regs[19]); + offset("#define PT_R20 ", struct pt_regs, regs[20]); + offset("#define PT_R21 ", struct pt_regs, regs[21]); + offset("#define PT_R22 ", struct pt_regs, regs[22]); + offset("#define PT_R23 ", struct pt_regs, regs[23]); + offset("#define PT_R24 ", struct pt_regs, regs[24]); + offset("#define PT_R25 ", struct pt_regs, regs[25]); + offset("#define PT_R26 ", struct pt_regs, regs[26]); + offset("#define PT_R27 ", struct pt_regs, regs[27]); + offset("#define PT_R28 ", struct pt_regs, regs[28]); + offset("#define PT_R29 ", struct pt_regs, regs[29]); + offset("#define PT_R30 ", struct pt_regs, regs[30]); + offset("#define PT_R31 ", struct pt_regs, regs[31]); + offset("#define PT_LO ", struct pt_regs, lo); + offset("#define PT_HI ", struct pt_regs, hi); + offset("#define PT_EPC ", struct pt_regs, cp0_epc); + offset("#define PT_BVADDR ", struct pt_regs, cp0_badvaddr); + offset("#define PT_STATUS ", struct pt_regs, cp0_status); + offset("#define PT_CAUSE ", struct pt_regs, cp0_cause); + size("#define PT_SIZE ", struct pt_regs); + linefeed; +} + +void output_task_defines(void) +{ + text("/* MIPS task_struct offsets. */"); + offset("#define TASK_STATE ", struct task_struct, state); + offset("#define TASK_FLAGS ", struct task_struct, flags); + offset("#define TASK_SIGPENDING ", struct task_struct, sigpending); + offset("#define TASK_NEED_RESCHED ", struct task_struct, need_resched); + offset("#define TASK_COUNTER ", struct task_struct, counter); + offset("#define TASK_PRIORITY ", struct task_struct, priority); + offset("#define TASK_MM ", struct task_struct, mm); + size("#define TASK_STRUCT_SIZE ", struct task_struct); + linefeed; +} + +void output_thread_defines(void) +{ + text("/* MIPS specific thread_struct offsets. */"); + offset("#define THREAD_REG16 ", struct task_struct, thread.reg16); + offset("#define THREAD_REG17 ", struct task_struct, thread.reg17); + offset("#define THREAD_REG18 ", struct task_struct, thread.reg18); + offset("#define THREAD_REG19 ", struct task_struct, thread.reg19); + offset("#define THREAD_REG20 ", struct task_struct, thread.reg20); + offset("#define THREAD_REG21 ", struct task_struct, thread.reg21); + offset("#define THREAD_REG22 ", struct task_struct, thread.reg22); + offset("#define THREAD_REG23 ", struct task_struct, thread.reg23); + offset("#define THREAD_REG29 ", struct task_struct, thread.reg29); + offset("#define THREAD_REG30 ", struct task_struct, thread.reg30); + offset("#define THREAD_REG31 ", struct task_struct, thread.reg31); + offset("#define THREAD_STATUS ", struct task_struct, \ + thread.cp0_status); + offset("#define THREAD_FPU ", struct task_struct, thread.fpu); + offset("#define THREAD_BVADDR ", struct task_struct, \ + thread.cp0_badvaddr); + offset("#define THREAD_BUADDR ", struct task_struct, \ + thread.cp0_baduaddr); + offset("#define THREAD_ECODE ", struct task_struct, \ + thread.error_code); + offset("#define THREAD_TRAPNO ", struct task_struct, thread.trap_no); + offset("#define THREAD_MFLAGS ", struct task_struct, thread.mflags); + offset("#define THREAD_CURDS ", struct task_struct, \ + thread.current_ds); + offset("#define THREAD_TRAMP ", struct task_struct, \ + thread.irix_trampoline); + offset("#define THREAD_OLDCTX ", struct task_struct, \ + thread.irix_oldctx); + linefeed; +} + +void output_mm_defines(void) +{ + text("/* Linux mm_struct offsets. */"); + offset("#define MM_USERS ", struct mm_struct, mm_users); + offset("#define MM_PGD ", struct mm_struct, pgd); + offset("#define MM_CONTEXT ", struct mm_struct, context); + linefeed; +} + +void output_sc_defines(void) +{ + text("/* Linux sigcontext offsets. */"); + offset("#define SC_REGS ", struct sigcontext, sc_regs); + offset("#define SC_FPREGS ", struct sigcontext, sc_fpregs); + offset("#define SC_MDHI ", struct sigcontext, sc_mdhi); + offset("#define SC_MDLO ", struct sigcontext, sc_mdlo); + offset("#define SC_PC ", struct sigcontext, sc_pc); + offset("#define SC_STATUS ", struct sigcontext, sc_status); + offset("#define SC_OWNEDFP ", struct sigcontext, sc_ownedfp); + offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); + offset("#define SC_FPC_EIR ", struct sigcontext, sc_fpc_eir); + offset("#define SC_CAUSE ", struct sigcontext, sc_cause); + offset("#define SC_BADVADDR ", struct sigcontext, sc_badvaddr); + linefeed; +} + +text("#endif /* !(_MIPS_OFFSET_H) */"); diff -u --recursive --new-file v2.3.47/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c --- v2.3.47/linux/arch/ppc/chrpboot/main.c Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/chrpboot/main.c Tue Feb 22 22:27:43 2000 @@ -10,7 +10,6 @@ #include "../coffboot/zlib.h" #include #include -#define __KERNEL__ #include extern void *finddevice(const char *); @@ -49,17 +48,8 @@ printf("chrpboot starting: loaded at 0x%x\n\r", &_start); - if (initrd_len) { - initrd_size = initrd_len; - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", initrd_start, - initrd_data,initrd_size); - memcpy((char *)initrd_start, initrd_data, initrd_size); - end_avail = (char *)initrd_start; - } else - end_avail = (char *) RAM_END; + end_avail = (char *) RAM_END; + im = image_data; len = image_len; dst = (void *) PROG_START; @@ -98,7 +88,7 @@ rec = (struct bi_record *)((unsigned long)rec + rec->size); rec->tag = BI_SYSMAP; - rec->data[0] = sysmap_data; + rec->data[0] = (unsigned long)sysmap_data; rec->data[1] = sysmap_len; rec->size = sizeof(struct bi_record) + sizeof(unsigned long); rec = (struct bi_record *)((unsigned long)rec + rec->size); @@ -129,6 +119,10 @@ void zfree(void *x, void *addr, unsigned nb) { + nb = (nb + 7) & -8; + if (addr == (avail_ram - nb)) { + avail_ram -= nb; + } } #define HEAD_CRC 2 diff -u --recursive --new-file v2.3.47/linux/arch/ppc/chrpboot/piggyback.c linux/arch/ppc/chrpboot/piggyback.c --- v2.3.47/linux/arch/ppc/chrpboot/piggyback.c Mon Jan 12 15:18:13 1998 +++ linux/arch/ppc/chrpboot/piggyback.c Tue Feb 22 22:27:43 2000 @@ -1,8 +1,9 @@ #include +#include extern long ce_exec_config[]; -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { int i, cnt, pos, len; unsigned int cksum, val; diff -u --recursive --new-file v2.3.47/linux/arch/ppc/coffboot/piggyback.c linux/arch/ppc/coffboot/piggyback.c --- v2.3.47/linux/arch/ppc/coffboot/piggyback.c Tue Dec 7 09:32:41 1999 +++ linux/arch/ppc/coffboot/piggyback.c Tue Feb 22 22:27:43 2000 @@ -1,8 +1,9 @@ #include +#include extern long ce_exec_config[]; -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { int i, cnt, pos, len; unsigned int cksum, val; diff -u --recursive --new-file v2.3.47/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.3.47/linux/arch/ppc/config.in Wed Feb 16 17:03:51 2000 +++ linux/arch/ppc/config.in Tue Feb 22 22:27:43 2000 @@ -47,12 +47,9 @@ fi if [ "$CONFIG_6xx" = "y" ]; then choice 'Machine Type' \ - "PowerMac CONFIG_PMAC \ - PReP/MTX CONFIG_PREP \ - CHRP CONFIG_CHRP \ - PowerMac/PReP/CHRP CONFIG_ALL_PPC \ + "PowerMac/PReP/MTX/CHRP CONFIG_ALL_PPC \ Gemini CONFIG_GEMINI \ - APUS CONFIG_APUS" PowerMac + APUS CONFIG_APUS" PowerMac/PReP/MTX/CHRP fi if [ "$CONFIG_PPC64" = "y" ]; then diff -u --recursive --new-file v2.3.47/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig --- v2.3.47/linux/arch/ppc/configs/common_defconfig Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/configs/common_defconfig Tue Feb 22 22:27:43 2000 @@ -17,9 +17,6 @@ # CONFIG_PPC64 is not set # CONFIG_82xx is not set # CONFIG_8xx is not set -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -# CONFIG_CHRP is not set CONFIG_ALL_PPC=y # CONFIG_GEMINI is not set # CONFIG_APUS is not set @@ -286,30 +283,29 @@ # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y +CONFIG_NET_PCI=y CONFIG_PCNET32=y # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set CONFIG_DE4X5=y -# CONFIG_DEC_ELCP is not set +# CONFIG_TULIP is not set # CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set # CONFIG_NE3210 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_RTL8129 is not set +# CONFIG_8139TOO is not set # CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set -# CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # @@ -499,6 +495,7 @@ # CONFIG_USB_DC2XX is not set # CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set +# CONFIG_USB_PLUSB is not set # # USB HID @@ -508,13 +505,15 @@ CONFIG_USB_MOUSE=y # CONFIG_USB_GRAPHIRE is not set # CONFIG_USB_WMFORCE is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_MIX is not set +# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_EVDEV is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y @@ -535,6 +534,7 @@ # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set diff -u --recursive --new-file v2.3.47/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.3.47/linux/arch/ppc/defconfig Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/defconfig Tue Feb 22 22:27:42 2000 @@ -17,9 +17,6 @@ # CONFIG_PPC64 is not set # CONFIG_82xx is not set # CONFIG_8xx is not set -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -# CONFIG_CHRP is not set CONFIG_ALL_PPC=y # CONFIG_GEMINI is not set # CONFIG_APUS is not set @@ -286,30 +283,29 @@ # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -CONFIG_NET_EISA=y +CONFIG_NET_PCI=y CONFIG_PCNET32=y # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_AC3200 is not set # CONFIG_APRICOT is not set -# CONFIG_CS89x0 is not set CONFIG_DE4X5=y -# CONFIG_DEC_ELCP is not set +# CONFIG_TULIP is not set # CONFIG_DGRS is not set -# CONFIG_EEXPRESS_PRO100 is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set # CONFIG_NE3210 is not set # CONFIG_NE2K_PCI is not set +# CONFIG_RTL8129 is not set +# CONFIG_8139TOO is not set # CONFIG_SIS900 is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set # CONFIG_ES3210 is not set # CONFIG_EPIC100 is not set -# CONFIG_ZNET is not set # CONFIG_NET_POCKET is not set # @@ -499,6 +495,7 @@ # CONFIG_USB_DC2XX is not set # CONFIG_USB_STORAGE is not set # CONFIG_USB_DABUSB is not set +# CONFIG_USB_PLUSB is not set # # USB HID @@ -508,13 +505,15 @@ CONFIG_USB_MOUSE=y # CONFIG_USB_GRAPHIRE is not set # CONFIG_USB_WMFORCE is not set -# CONFIG_INPUT_KEYBDEV is not set -# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_MIX is not set +# CONFIG_INPUT_MOUSEDEV_DIGITIZER is not set # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_EVDEV is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y @@ -535,6 +534,7 @@ # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile --- v2.3.47/linux/arch/ppc/kernel/Makefile Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/kernel/Makefile Thu Feb 24 22:43:13 2000 @@ -88,24 +88,14 @@ ifeq ($(CONFIG_NVRAM),y) O_OBJS += pmac_nvram.o endif -ifeq ($(CONFIG_6xx),y) - O_OBJS += open_pic.o indirect_pci.o -endif -ifeq ($(CONFIG_PPC64),y) - O_OBJS += open_pic.o indirect_pci.o -endif ifeq ($(CONFIG_APUS),y) O_OBJS += apus_setup.o endif -ifeq ($(CONFIG_PMAC),y) - O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o -endif -ifeq ($(CONFIG_CHRP),y) - O_OBJS += chrp_pci.o pmac_pci.o chrp_setup.o i8259.o \ - chrp_time.o pmac_time.o prom.o -endif -ifeq ($(CONFIG_PREP),y) - O_OBJS += prep_pci.o i8259.o prep_setup.o prep_nvram.o prep_time.o residual.o +ifeq ($(CONFIG_ALL_PPC),y) + O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o \ + chrp_setup.o chrp_time.o chrp_pci.o open_pic.o indirect_pci.o \ + prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o + OX_OBJS += prep_setup.o endif ifeq ($(CONFIG_GEMINI),y) O_OBJS += gemini_prom.o gemini_pci.o gemini_setup.o diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c --- v2.3.47/linux/arch/ppc/kernel/apus_setup.c Thu Feb 10 17:11:04 2000 +++ linux/arch/ppc/kernel/apus_setup.c Tue Feb 22 22:27:43 2000 @@ -10,7 +10,7 @@ * TODO: * This file needs a *really* good cleanup. Restructure and optimize. * Make sure it can be compiled for non-APUS configs. Begin to move - * Amiga specific stuff into linux/machine/amiga. + * Amiga specific stuff into mach/amiga. */ #include @@ -27,6 +27,10 @@ #include #endif +/* Needs INITSERIAL call in head.S! */ +#undef APUS_DEBUG + + #include #define T_CHAR (0x0000) /* char: don't touch */ #define T_SHORT (0x4000) /* short: 12 -> 21 */ @@ -60,37 +64,6 @@ #define num_driveid_types (sizeof(driveid_types)/sizeof(*driveid_types)) -#if 0 /* Get rid of this crud */ -/* Get the IDE stuff from the 68k file */ -#define ide_init_hwif_ports m68k_ide_init_hwif_ports -#define ide_default_irq m68k_ide_default_irq -#undef ide_request_irq -#define ide_request_irq m68k_ide_request_irq -#undef ide_free_irq -#define ide_free_irq m68k_ide_free_irq -#define ide_default_io_base m68k_ide_default_io_base -#define ide_check_region m68k_ide_check_region -#define ide_request_region m68k_ide_request_region -#define ide_release_region m68k_ide_release_region -#define ide_fix_driveid m68k_ide_fix_driveid -#define ide_init_default_hwifs m68k_ide_init_default_hwifs -#define select_t m68k_select_t -//#include -#include -#undef ide_free_irq -#undef select_t -#undef ide_request_irq -#undef ide_init_default_hwifs -#undef ide_init_hwif_ports -#undef ide_default_irq -#undef ide_default_io_base -#undef ide_check_region -#undef ide_request_region -#undef ide_release_region -#undef ide_fix_driveid -/*-------------------------------------------*/ -#endif - #include #include #include @@ -764,6 +737,12 @@ /****************************************************** IRQ stuff */ __apus +static unsigned int apus_irq_cannonicalize(unsigned int irq) +{ + return irq; +} + +__apus int apus_get_irq_list(char *buf) { #ifdef CONFIG_APUS @@ -922,6 +901,114 @@ } +/****************************************************** debugging */ + +/* some serial hardware definitions */ +#define SDR_OVRUN (1<<15) +#define SDR_RBF (1<<14) +#define SDR_TBE (1<<13) +#define SDR_TSRE (1<<12) + +#define AC_SETCLR (1<<15) +#define AC_UARTBRK (1<<11) + +#define SER_DTR (1<<7) +#define SER_RTS (1<<6) +#define SER_DCD (1<<5) +#define SER_CTS (1<<4) +#define SER_DSR (1<<3) + +static __inline__ void ser_RTSon(void) +{ + ciab.pra &= ~SER_RTS; /* active low */ +} + +__apus +int __debug_ser_out( unsigned char c ) +{ + custom.serdat = c | 0x100; + mb(); + while (!(custom.serdatr & 0x2000)) + barrier(); + return 1; +} + +__apus +unsigned char __debug_ser_in( void ) +{ + unsigned char c; + + /* XXX: is that ok?? derived from amiga_ser.c... */ + while( !(custom.intreqr & IF_RBF) ) + barrier(); + c = custom.serdatr; + /* clear the interrupt, so that another character can be read */ + custom.intreq = IF_RBF; + return c; +} + +__apus +int __debug_serinit( void ) +{ + unsigned long flags; + + save_flags (flags); + cli(); + + /* turn off Rx and Tx interrupts */ + custom.intena = IF_RBF | IF_TBE; + + /* clear any pending interrupt */ + custom.intreq = IF_RBF | IF_TBE; + + restore_flags (flags); + + /* + * set the appropriate directions for the modem control flags, + * and clear RTS and DTR + */ + ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */ + ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */ + +#ifdef CONFIG_KGDB + /* turn Rx interrupts on for GDB */ + custom.intena = IF_SETCLR | IF_RBF; + ser_RTSon(); +#endif + + return 0; +} + +__apus +void __debug_print_hex(unsigned long x) +{ + int i; + char hexchars[] = "0123456789ABCDEF"; + + for (i = 0; i < 8; i++) { + __debug_ser_out(hexchars[(x >> 28) & 15]); + x <<= 4; + } + __debug_ser_out('\n'); + __debug_ser_out('\r'); +} + +__apus +void __debug_print_string(char* s) +{ + unsigned char c; + while((c = *s++)) + __debug_ser_out(c); + __debug_ser_out('\n'); + __debug_ser_out('\r'); +} + +__apus +static void apus_progress(char *s, unsigned short value) +{ + __debug_print_string(s); +} + /****************************************************** init */ /* The number of spurious interrupts */ @@ -970,7 +1057,7 @@ int i; for ( i = 0 ; i < NR_IRQS ; i++ ) - irq_desc[i].ctl = &amiga_irqctrl; + irq_desc[i].handler = &amiga_irqctrl; for (i = 0; i < NUM_IRQ_NODES; i++) nodes[i].handler = NULL; @@ -1015,13 +1102,17 @@ ppc_md.setup_arch = apus_setup_arch; ppc_md.setup_residual = NULL; ppc_md.get_cpuinfo = apus_get_cpuinfo; - ppc_md.irq_cannonicalize = NULL; + ppc_md.irq_cannonicalize = apus_irq_cannonicalize; ppc_md.init_IRQ = apus_init_IRQ; ppc_md.get_irq = apus_get_irq; ppc_md.post_irq = apus_post_irq; #ifdef CONFIG_HEARTBEAT ppc_md.heartbeat = apus_heartbeat; ppc_md.heartbeat_count = 1; +#endif +#ifdef APUS_DEBUG + __debug_serinit(); + ppc_md.progress = apus_progress; #endif ppc_md.init = NULL; diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S --- v2.3.47/linux/arch/ppc/kernel/entry.S Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/kernel/entry.S Tue Feb 22 22:27:42 2000 @@ -435,7 +435,7 @@ * here so it's easy to add arch-specific sections later. * -- Cort */ -#if defined(CONFIG_CHRP) || defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* * On CHRP, the Run-Time Abstraction Services (RTAS) have to be * called with the MMU off. @@ -475,4 +475,4 @@ mtspr SRR0,r8 mtspr SRR1,r9 rfi /* return to caller */ -#endif /* CONFIG_CHRP || CONFIG_PMAC || CONFIG_ALL_PPC */ +#endif /* CONFIG_ALL_PPC */ diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/hashtable.S linux/arch/ppc/kernel/hashtable.S --- v2.3.47/linux/arch/ppc/kernel/hashtable.S Fri Oct 15 15:25:13 1999 +++ linux/arch/ppc/kernel/hashtable.S Tue Feb 22 22:27:43 2000 @@ -115,11 +115,6 @@ stw r6,0(r2) /* update PTE (accessed/dirty bits) */ /* Convert linux-style PTE to low word of PPC-style PTE */ -#ifdef CONFIG_PPC64 - /* clear the high 32 bits just in case */ - clrldi r6,r6,32 - clrldi r4,r4,32 -#endif /* CONFIG_PPC64 */ rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ ori r4,r4,0xe04 /* clear out reserved bits */ @@ -151,10 +146,6 @@ .globl hash_page_patch_A hash_page_patch_A: lis r4,Hash_base@h /* base address of hash table */ -#ifdef CONFIG_PPC64 - /* just in case */ - clrldi r4,r4,32 -#endif rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */ rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */ xor r4,r4,r0 /* make primary hash */ @@ -169,43 +160,89 @@ /* Search the primary PTEG for a PTE whose 1st word matches r5 */ mtctr r2 addi r3,r4,-8 -1: lwzu r0,8(r3) /* get next PTE */ +1: +#ifdef CONFIG_PPC64 + lwzu r0,16(r3) /* get next PTE */ +#else + lwzu r0,8(r3) /* get next PTE */ +#endif cmp 0,r0,r5 bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_slot /* Search the secondary PTEG for a matching PTE */ +#ifdef CONFIG_PPC64 + ori r5,r5,0x2 /* set H (secondary hash) bit */ +#else ori r5,r5,0x40 /* set H (secondary hash) bit */ +#endif .globl hash_page_patch_B hash_page_patch_B: xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ xori r3,r3,0xffc0 +#ifdef CONFIG_PPC64 + addi r3,r3,-16 +#else addi r3,r3,-8 +#endif mtctr r2 -2: lwzu r0,8(r3) +2: +#ifdef CONFIG_PPC64 + lwzu r0,16(r3) +#else + lwzu r0,8(r3) +#endif cmp 0,r0,r5 bdnzf 2,2b beq+ found_slot +#ifdef CONFIG_PPC64 + xori r5,r5,0x2 /* clear H bit again */ +#else xori r5,r5,0x40 /* clear H bit again */ +#endif /* Search the primary PTEG for an empty slot */ 10: mtctr r2 +#ifdef CONFIG_PPC64 + addi r3,r4,-16 /* search primary PTEG */ +#else addi r3,r4,-8 /* search primary PTEG */ -1: lwzu r0,8(r3) /* get next PTE */ +#endif +1: +#ifdef CONFIG_PPC64 + lwzu r0,16(r3) /* get next PTE */ + andi. r0,r0,1 +#else + lwzu r0,8(r3) /* get next PTE */ rlwinm. r0,r0,0,0,0 /* only want to check valid bit */ +#endif bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */ beq+ found_empty /* Search the secondary PTEG for an empty slot */ +#ifdef CONFIG_PPC64 + ori r5,r5,0x2 /* set H (secondary hash) bit */ +#else ori r5,r5,0x40 /* set H (secondary hash) bit */ +#endif .globl hash_page_patch_C hash_page_patch_C: xoris r3,r4,Hash_msk>>16 /* compute secondary hash */ xori r3,r3,0xffc0 +#ifdef CONFIG_PPC64 + addi r3,r3,-16 +#else addi r3,r3,-8 +#endif mtctr r2 -2: lwzu r0,8(r3) +2: +#ifdef CONFIG_PPC64 + lwzu r0,16(r3) + andi. r0,r0,1 +#else + lwzu r0,8(r3) rlwinm. r0,r0,0,0,0 /* only want to check valid bit */ +#endif bdnzf 2,2b beq+ found_empty @@ -218,12 +255,21 @@ * advantage to putting the PTE in the primary PTEG, we always * put the PTE in the primary PTEG. */ +#ifdef CONFIG_PPC64 + xori r5,r5,0x2 /* clear H bit again */ +#else xori r5,r5,0x40 /* clear H bit again */ +#endif lis r3,next_slot@ha tophys(r3,r3) lwz r2,next_slot@l(r3) +#ifdef CONFIG_PPC64 + addi r2,r2,16 + andi. r2,r2,0x78 +#else addi r2,r2,8 andi. r2,r2,0x38 +#endif stw r2,next_slot@l(r3) add r3,r4,r2 11: @@ -237,9 +283,17 @@ #ifndef __SMP__ /* Store PTE in PTEG */ found_empty: +#ifdef CONFIG_PPC64 + std r5,0(r3) +#else stw r5,0(r3) +#endif found_slot: +#ifdef CONFIG_PPC64 + std r6,8(r3) +#else stw r6,4(r3) +#endif sync #else /* __SMP__ */ diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.3.47/linux/arch/ppc/kernel/head.S Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/kernel/head.S Tue Feb 22 22:27:43 2000 @@ -1328,18 +1328,15 @@ /* Load the SDR1 register (hash table base & size) */ lis r6,_SDR1@ha tophys(r6,r6) -#ifdef CONFIG_PPC64 - ld r6,_SDR1@l(r6) + lwz r6,_SDR1@l(r6) mtspr SDR1,r6 +#ifdef CONFIG_PPC64 /* clear the v bit in the ASR so we can * behave as if we have segment registers * -- Cort */ clrldi r6,r6,63 mtasr r6 -#else - lwz r6,_SDR1@l(r6) - mtspr SDR1,r6 #endif /* CONFIG_PPC64 */ li r0,16 /* load up segment register values */ mtctr r0 /* for context 0 */ diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.3.47/linux/arch/ppc/kernel/irq.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/kernel/irq.c Tue Feb 22 22:27:43 2000 @@ -70,8 +70,6 @@ #define MAXCOUNT 10000000 -#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) - irq_desc_t irq_desc[NR_IRQS]; int ppc_spurious_interrupts = 0; unsigned int local_bh_count[NR_CPUS]; @@ -80,7 +78,6 @@ unsigned int ppc_cached_irq_mask[NR_MASK_WORDS]; unsigned int ppc_lost_interrupts[NR_MASK_WORDS]; atomic_t ppc_n_lost_interrupts; - /* nasty hack for shared irq's since we need to do kmalloc calls but * can't very early in the boot when we need to do a request irq. diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.3.47/linux/arch/ppc/kernel/misc.S Wed Feb 16 17:03:51 2000 +++ linux/arch/ppc/kernel/misc.S Tue Feb 22 22:27:43 2000 @@ -241,12 +241,21 @@ rlwinm r5,r5,16,16,31 cmpi 0,r5,1 beqlr /* for 601, do nothing */ + li r4,0x0FFF + andc r3,r3,r4 /* Get page base address */ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */ mtctr r4 + mr r6,r3 0: dcbst 0,r3 /* Write line to ram */ addi r3,r3,CACHE_LINE_SIZE bdnz 0b sync + mtctr r4 +1: icbi 0,r6 + addi r6,r6,CACHE_LINE_SIZE + bdnz 1b + sync + isync blr /* @@ -270,7 +279,7 @@ sync isync blr - + /* * Clear a page using the dcbz instruction, which doesn't cause any * memory traffic (except to write out any cache lines which get diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c --- v2.3.47/linux/arch/ppc/kernel/mk_defs.c Wed Feb 16 17:03:51 2000 +++ linux/arch/ppc/kernel/mk_defs.c Tue Feb 22 22:27:43 2000 @@ -99,6 +99,7 @@ DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); + DEFINE(_MQ, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq)); DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.3.47/linux/arch/ppc/kernel/pmac_pic.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/kernel/pmac_pic.c Tue Feb 22 22:27:43 2000 @@ -39,6 +39,17 @@ extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val); +/* + * Mark an irq as "lost". This is only used on the pmac + * since it can lose interrupts (see pmac_set_irq_mask). + * -- Cort + */ +void __pmac __no_use_set_lost(unsigned long irq_nr) +{ + if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) + atomic_inc(&ppc_n_lost_interrupts); +} + static void pmac_openpic_mask_irq(unsigned int irq_nr) { openpic_disable_irq(irq_nr); @@ -105,10 +116,8 @@ */ if ((bit & ppc_cached_irq_mask[i]) && (ld_le32(&pmac_irq_hw[i]->level) & bit) - && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) { - if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) - atomic_inc(&ppc_n_lost_interrupts); - } + && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) + __set_lost((ulong)irq_nr); } static void __pmac pmac_mask_irq(unsigned int irq_nr) @@ -174,6 +183,8 @@ unsigned long bits = 0; #ifdef __SMP__ + void pmac_smp_message_recv(void); + /* IPI's are a hack on the powersurge -- Cort */ if ( smp_processor_id() != 0 ) { @@ -182,12 +193,12 @@ if (xmon_2nd) xmon(regs); #endif - smp_message_recv(); + pmac_smp_message_recv(); return -2; /* ignore, already handled */ } #endif /* __SMP__ */ - /* Yeah, I know, this could be a separate do_IRQ function */ + /* Yeah, I know, this could be a separate get_irq function */ if (has_openpic) { irq = openpic_irq(smp_processor_id()); @@ -376,6 +387,7 @@ irqctrler = NULL; } + int_control.int_set_lost = __no_use_set_lost; /* * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts, * 1998 G3 Series PowerBooks have 128, diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c --- v2.3.47/linux/arch/ppc/kernel/ppc_htab.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/kernel/ppc_htab.c Sat Feb 26 20:33:02 2000 @@ -44,17 +44,10 @@ extern unsigned long pte_misses; extern unsigned long pte_errors; -static struct file_operations ppc_htab_operations = { +struct file_operations ppc_htab_operations = { llseek: ppc_htab_lseek, read: ppc_htab_read, write: ppc_htab_write, -}; - -/* - * proc files can do almost nothing.. - */ -struct inode_operations proc_ppc_htab_inode_operations = { - &ppc_htab_operations, /* default proc file-ops */ }; /* these will go into processor.h when I'm done debugging -- Cort */ diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.3.47/linux/arch/ppc/kernel/ppc_ksyms.c Wed Feb 16 17:03:51 2000 +++ linux/arch/ppc/kernel/ppc_ksyms.c Tue Feb 22 22:27:43 2000 @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef __SMP__ #include #endif /* __SMP__ */ @@ -50,7 +51,6 @@ extern void ProgramCheckException(struct pt_regs *regs); extern void SingleStepException(struct pt_regs *regs); extern int sys_sigreturn(struct pt_regs *regs); -extern atomic_t ppc_n_lost_interrupts; extern void do_lost_interrupts(unsigned long); extern int do_signal(sigset_t *, struct pt_regs *); @@ -69,6 +69,7 @@ EXPORT_SYMBOL(SingleStepException); EXPORT_SYMBOL(sys_sigreturn); EXPORT_SYMBOL(ppc_n_lost_interrupts); +EXPORT_SYMBOL(ppc_lost_interrupts); EXPORT_SYMBOL(do_lost_interrupts); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); @@ -88,7 +89,7 @@ EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); #ifndef CONFIG_8xx -#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(_prep_type); EXPORT_SYMBOL(ucSystemType); #endif @@ -125,7 +126,6 @@ EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strspn); EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strncmp); @@ -227,7 +227,7 @@ EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); #endif CONFIG_PMAC_PBOOK -#if defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -243,8 +243,8 @@ EXPORT_SYMBOL(feature_set); EXPORT_SYMBOL(feature_clear); EXPORT_SYMBOL(feature_test); -#endif /* defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC) */ -#if defined(CONFIG_SCSI) && (defined(CONFIG_PMAC) || defined(CONFIG_ALL_PPC)) +#endif /* defined(CONFIG_ALL_PPC) */ +#if defined(CONFIG_SCSI) && defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(note_scsi_host); #endif EXPORT_SYMBOL(kd_mksound); @@ -270,7 +270,6 @@ EXPORT_SYMBOL(int_control); EXPORT_SYMBOL(timer_interrupt_intercept); EXPORT_SYMBOL(timer_interrupt); -extern unsigned long do_IRQ_intercept; EXPORT_SYMBOL(do_IRQ_intercept); EXPORT_SYMBOL(irq_desc); void ppc_irq_dispatch_handler(struct pt_regs *, int); @@ -278,3 +277,7 @@ EXPORT_SYMBOL(decrementer_count); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); +#ifdef CONFIG_XMON +EXPORT_SYMBOL(xmon); +#endif +EXPORT_SYMBOL(down_read_failed); diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.3.47/linux/arch/ppc/kernel/process.c Wed Feb 16 17:03:51 2000 +++ linux/arch/ppc/kernel/process.c Tue Feb 22 22:27:43 2000 @@ -158,7 +158,7 @@ if (current->thread.regs && (current->thread.regs->msr & MSR_VEC)) giveup_altivec(current); else - giveup_altivec(NULL): /* just enable AltiVec for kernel - force */ + giveup_altivec(NULL); /* just enable AltiVec for kernel - force */ #else giveup_altivec(last_task_used_altivec); #endif /* __SMP __ */ diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.3.47/linux/arch/ppc/kernel/prom.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/kernel/prom.c Tue Feb 22 22:27:43 2000 @@ -604,7 +604,6 @@ /* XXX: hack - don't start cpu 0, this cpu -- Cort */ if ( smp_chrp_cpu_nr++ == 0 ) continue; - RELOC(smp_ibm_chrp_hack) = 1; prom_print(RELOC("starting cpu ")); prom_print(path); *(unsigned long *)(0x4) = 0; diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.3.47/linux/arch/ppc/kernel/setup.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/kernel/setup.c Sat Feb 26 20:32:13 2000 @@ -733,17 +733,13 @@ id->eide_dma_time = __le16_to_cpu(id->eide_dma_time); id->eide_pio = __le16_to_cpu(id->eide_pio); id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy); - id->word69 = __le16_to_cpu(id->word69); - id->word70 = __le16_to_cpu(id->word70); - id->word71 = __le16_to_cpu(id->word71); - id->word72 = __le16_to_cpu(id->word72); - id->word73 = __le16_to_cpu(id->word73); - id->word74 = __le16_to_cpu(id->word74); + for (i=0; i<2 i++) + id->words69_70[i] = __le16_to_cpu(id->words69_70[i]); + for (i=0; i<4 i++) + id->words71_74[i] = __le16_to_cpu(id->words71_74[i]); id->queue_depth = __le16_to_cpu(id->queue_depth); - id->word76 = __le16_to_cpu(id->word76); - id->word77 = __le16_to_cpu(id->word77); - id->word78 = __le16_to_cpu(id->word78); - id->word79 = __le16_to_cpu(id->word79); + for (i=0; i<4 i++) + id->words76_79[i] = __le16_to_cpu(id->words76_79[i]); id->major_rev_num = __le16_to_cpu(id->major_rev_num); id->minor_rev_num = __le16_to_cpu(id->minor_rev_num); id->command_set_1 = __le16_to_cpu(id->command_set_1); @@ -758,40 +754,14 @@ id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); id->word92 = __le16_to_cpu(id->word92); id->hw_config = __le16_to_cpu(id->hw_config); - id->word94 = __le16_to_cpu(id->word94); - id->word95 = __le16_to_cpu(id->word95); - id->word96 = __le16_to_cpu(id->word96); - id->word97 = __le16_to_cpu(id->word97); - id->word98 = __le16_to_cpu(id->word98); - id->word99 = __le16_to_cpu(id->word99); - id->word100 = __le16_to_cpu(id->word100); - id->word101 = __le16_to_cpu(id->word101); - id->word102 = __le16_to_cpu(id->word102); - id->word103 = __le16_to_cpu(id->word103); - id->word104 = __le16_to_cpu(id->word104); - id->word105 = __le16_to_cpu(id->word105); - id->word106 = __le16_to_cpu(id->word106); - id->word107 = __le16_to_cpu(id->word107); - id->word108 = __le16_to_cpu(id->word108); - id->word109 = __le16_to_cpu(id->word109); - id->word110 = __le16_to_cpu(id->word110); - id->word111 = __le16_to_cpu(id->word111); - id->word112 = __le16_to_cpu(id->word112); - id->word113 = __le16_to_cpu(id->word113); - id->word114 = __le16_to_cpu(id->word114); - id->word115 = __le16_to_cpu(id->word115); - id->word116 = __le16_to_cpu(id->word116); - id->word117 = __le16_to_cpu(id->word117); - id->word118 = __le16_to_cpu(id->word118); - id->word119 = __le16_to_cpu(id->word119); - id->word120 = __le16_to_cpu(id->word120); - id->word121 = __le16_to_cpu(id->word121); - id->word122 = __le16_to_cpu(id->word122); - id->word123 = __le16_to_cpu(id->word123); - id->word124 = __le16_to_cpu(id->word124); - id->word125 = __le16_to_cpu(id->word125); - id->word126 = __le16_to_cpu(id->word126); + for (i=0; i<34; i++) + id->words94_125[i] = __le16_to_cpu(id->words94_125[i]); + id->last_lun = __le16_to_cpu(id->last_lun); id->word127 = __le16_to_cpu(id->word127); - for (i=0; i<127; i++) - id->reserved[i] = __le16_to_cpu(id->reserved[i]); + id->dlf = __le16_to_cpu(id->dlf); + id->csfo = __le16_to_cpu(id->csfo); + for (i=0; i<31; i++) + id->words130_159[i] = __le16_to_cpu(id->words130_159[i]); + for (i=0; i<97; i++) + id->words160_255[i] = __le16_to_cpu(id->words160_255[i]); } diff -u --recursive --new-file v2.3.47/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.3.47/linux/arch/ppc/kernel/smp.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/kernel/smp.c Thu Feb 24 10:11:24 2000 @@ -12,6 +12,7 @@ * (troy@microux.com, hozer@drgw.net) */ +#include #include #include #include @@ -445,8 +446,10 @@ */ if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) ) do_openpic_setup_cpu(); +#ifdef CONFIG_GEMINI if ( _machine == _MACH_gemini ) gemini_init_l2(); +#endif while(!smp_commenced) barrier(); __sti(); diff -u --recursive --new-file v2.3.47/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.3.47/linux/arch/ppc/mm/init.c Sun Feb 13 19:29:03 2000 +++ linux/arch/ppc/mm/init.c Thu Feb 24 22:43:13 2000 @@ -115,11 +115,7 @@ PTE *Hash, *Hash_end; unsigned long Hash_size, Hash_mask; #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -#ifdef CONFIG_PPC64 -unsigned long long _SDR1; -#else unsigned long _SDR1; -#endif static void hash_init(void); union ubat { /* BAT register values to be loaded */ @@ -423,10 +419,9 @@ /* * Is it a candidate for a BAT mapping? */ - for (i = 0; i < size; i += PAGE_SIZE) map_page(v+i, p+i, flags); -out: +out: return (void *) (v + (addr & ~PAGE_MASK)); } @@ -593,7 +588,7 @@ #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) static void get_mem_prop(char *, struct mem_pieces *); -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* * Read in a property describing some pieces of memory. */ @@ -616,7 +611,7 @@ mem_pieces_sort(mp); mem_pieces_coalesce(mp); } -#endif /* CONFIG_PMAC || CONFIG_CHRP || CONFIG_ALL_PPC */ +#endif /* CONFIG_ALL_PPC */ /* * Set up one of the I/D BAT (block address translation) register pairs. @@ -921,10 +916,11 @@ if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); #ifdef CONFIG_PPC64 - _SDR1 = 0; /* temporary hack to just use bats -- Cort */ -#else + _SDR1 = __pa(Hash) | (ffz(~Hash_size) - 7)-11; +#else _SDR1 = __pa(Hash) | (Hash_mask >> 10); -#endif +#endif + ioremap_base = 0xf8000000; if ( ppc_md.progress ) ppc_md.progress("MMU:mapin", 0x301); @@ -947,7 +943,7 @@ setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE); #ifdef CONFIG_PPC64 /* temporary hack to get working until page tables are stable -- Cort*/ - setbat(1, 0x80000000, 0xc0000000, 0x10000000, IO_PAGE); +/* setbat(1, 0x80000000, 0xc0000000, 0x10000000, IO_PAGE);*/ setbat(3, 0xd0000000, 0xd0000000, 0x10000000, IO_PAGE); #else setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE); @@ -1118,7 +1114,7 @@ /* * All pages are DMA-able so we put them all in the DMA zone. */ - zones_size[0] = virt_to_phys(end_of_DRAM) >> PAGE_SHIFT; + zones_size[0] = ((unsigned long)end_of_DRAM - KERNELBASE) >> PAGE_SHIFT; for (i = 1; i < MAX_NR_ZONES; i++) zones_size[i] = 0; free_area_init(zones_size); @@ -1132,9 +1128,9 @@ int codepages = 0; int datapages = 0; int initpages = 0; -#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) extern unsigned int rtas_data, rtas_size; -#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */ +#endif /* defined(CONFIG_ALL_PPC) */ max_mapnr = max_low_pfn; high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); num_physpages = max_mapnr; /* RAM is assumed contiguous */ @@ -1150,13 +1146,13 @@ } #endif /* CONFIG_BLK_DEV_INITRD */ -#if defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* mark the RTAS pages as reserved */ if ( rtas_data ) for (addr = rtas_data; addr < PAGE_ALIGN(rtas_data+rtas_size) ; addr += PAGE_SIZE) SetPageReserved(mem_map + MAP_NR(addr)); -#endif /* defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) */ +#endif /* defined(CONFIG_ALL_PPC) */ if ( sysmap_size ) for (addr = (unsigned long)sysmap; addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ; @@ -1178,13 +1174,14 @@ printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n", (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), - codepages, datapages, initpages, + codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), + initpages<< (PAGE_SHIFT-10), PAGE_OFFSET, (unsigned long) end_of_DRAM); mem_init_done = 1; } #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* * On systems with Open Firmware, collect information about * physical RAM and which pieces are already in use. @@ -1195,9 +1192,13 @@ unsigned long __init *pmac_find_end_of_memory(void) { unsigned long a, total; - - /* max amount of RAM we allow -- Cort */ -#define RAM_LIMIT (768<<20) + unsigned long ram_limit = 0xf0000000 - KERNELBASE; + /* allow 0x08000000 for IO space */ + if ( _machine & (_MACH_prep|_MACH_Pmac) ) + ram_limit = 0xd8000000 - KERNELBASE; +#ifdef CONFIG_PPC64 + ram_limit = 64<<20; +#endif memory_node = find_devices("memory"); if (memory_node == NULL) { @@ -1222,16 +1223,8 @@ a = phys_mem.regions[0].address; if (a != 0) panic("RAM doesn't start at physical address 0"); - /* - * XXX: - * Make sure ram mappings don't stomp on IO space - * This is a temporary hack to keep this from happening - * until we move the KERNELBASE and can allocate RAM up - * to our nearest IO area. - * -- Cort - */ - if (__max_memory == 0 || __max_memory > RAM_LIMIT) - __max_memory = RAM_LIMIT; + if (__max_memory == 0 || __max_memory > ram_limit) + __max_memory = ram_limit; if (phys_mem.regions[0].size >= __max_memory) { phys_mem.regions[0].size = __max_memory; phys_mem.n_regions = 1; @@ -1247,12 +1240,11 @@ set_phys_avail(&phys_mem); -#undef RAM_LIMIT return __va(total); } -#endif /* CONFIG_PMAC || CONFIG_CHRP || CONFIG_ALL_PPC */ +#endif /* CONFIG_ALL_PPC */ -#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_ALL_PPC) /* * This finds the amount of physical ram and does necessary * setup for prep. This is pretty architecture specific so @@ -1279,7 +1271,7 @@ return (__va(total)); } -#endif /* defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC) */ +#endif /* defined(CONFIG_ALL_PPC) */ #if defined(CONFIG_GEMINI) @@ -1389,16 +1381,12 @@ * up to a maximum of 2MB. */ ramsize = (ulong)end_of_DRAM - KERNELBASE; -#ifdef CONFIG_PPC64 - Hash_mask = 0; - for (h = 256<<10; h < ramsize / 256 && h < 4<<20; h *= 2, Hash_mask++) - ; - Hash_size = h; - Hash_mask <<= 10; /* so setting _SDR1 works the same -- Cort */ -#else for (h = 64<<10; h < ramsize / 256 && h < 2<<20; h *= 2) ; Hash_size = h; +#ifdef CONFIG_PPC64 + Hash_mask = (h >> 7) - 1; +#else Hash_mask = (h >> 6) - 1; #endif @@ -1433,7 +1421,11 @@ /* * Patch up the instructions in head.S:hash_page */ +#ifdef CONFIG_PPC64 + Hash_bits = ffz(~Hash_size) - 7; +#else Hash_bits = ffz(~Hash_size) - 6; +#endif hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff) | (__pa(Hash) >> 16); hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) @@ -1443,9 +1435,17 @@ hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) | ((26 - Hash_bits) << 6); hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) +#ifdef CONFIG_PPC64 + | (Hash_mask >> 11); +#else | (Hash_mask >> 10); +#endif hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) +#ifdef CONFIG_PPC64 + | (Hash_mask >> 11); +#else | (Hash_mask >> 10); +#endif #if 0 /* see hash_page in head.S, note also patch_C ref below */ hash_page_patch_D[0] = (hash_page_patch_D[0] & ~0xffff) | (Hash_mask >> 10); diff -u --recursive --new-file v2.3.47/linux/arch/ppc/mm/mem_pieces.c linux/arch/ppc/mm/mem_pieces.c --- v2.3.47/linux/arch/ppc/mm/mem_pieces.c Tue Jan 11 22:31:38 2000 +++ linux/arch/ppc/mm/mem_pieces.c Tue Feb 22 22:27:43 2000 @@ -127,7 +127,7 @@ printk("\n"); } -#if defined(CONFIG_PREP) || defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) /* * Add some memory to an array of pieces */ diff -u --recursive --new-file v2.3.47/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c --- v2.3.47/linux/arch/ppc/xmon/xmon.c Thu Feb 10 17:11:05 2000 +++ linux/arch/ppc/xmon/xmon.c Tue Feb 22 22:27:43 2000 @@ -75,11 +75,14 @@ static unsigned read_spr(int); static void write_spr(int, unsigned); static void super_regs(void); +static void print_sysmap(void); static void remove_bpts(void); static void insert_bpts(void); static struct bpt *at_breakpoint(unsigned pc); static void bpt_cmds(void); static void cacheflush(void); +static char *pretty_lookup_name(unsigned long addr); +static char *lookup_name(unsigned long addr); extern int print_insn_big_powerpc(FILE *, unsigned long, unsigned); extern void printf(const char *fmt, ...); @@ -101,6 +104,7 @@ mm move a block of memory\n\ ms set a block of memory\n\ md compare two blocks of memory\n\ + M print System.map\n\ r print registers\n\ S print special registers\n\ t print backtrace\n\ @@ -337,6 +341,8 @@ else excprint(excp); break; + case 'M': + print_sysmap(); case 'S': super_regs(); break; @@ -514,8 +520,10 @@ void excprint(struct pt_regs *fp) { - printf("vector: %x at pc = %x, msr = %x, sp = %x [%x]\n", - fp->trap, fp->nip, fp->msr, fp->gpr[1], fp); + printf("vector: %x at pc = %x %s", + fp->trap, fp->nip,/* pretty_lookup_name(fp->nip)*/""); + printf(", msr = %x, sp = %x [%x]\n", + fp->msr, fp->gpr[1], fp); if (fp->trap == 0x300 || fp->trap == 0x600) printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr); if (current) @@ -597,6 +605,14 @@ 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; @@ -1345,9 +1361,26 @@ lineptr = str; } +/* + * We use this array a lot here. We assume we don't have multiple + * instances of xmon running and that we don't use the return value of + * any functions other than printing them. + * -- Cort + */ char last[64]; -char * -lookup_addr(unsigned long addr) +static char *pretty_lookup_name(unsigned long addr) +{ + if ( lookup_name(addr) ) + { + sprintf(last, " (%s)", lookup_name(addr)); + return last; + } + else + return NULL; +} + + +static char *lookup_name(unsigned long addr) { extern char *sysmap; extern unsigned long sysmap_size; @@ -1357,10 +1390,6 @@ if ( !sysmap || !sysmap_size ) return NULL; - /* adjust if addr is relative to kernelbase */ - if ( addr < PAGE_OFFSET ) - addr += PAGE_OFFSET; - cmp = simple_strtoul(c, &c, 8); strcpy( last, strsep( &c, "\n")); while ( c < (sysmap+sysmap_size) ) @@ -1372,3 +1401,4 @@ } return last; } + diff -u --recursive --new-file v2.3.47/linux/arch/sparc/boot/Makefile linux/arch/sparc/boot/Makefile --- v2.3.47/linux/arch/sparc/boot/Makefile Tue Oct 27 09:52:20 1998 +++ linux/arch/sparc/boot/Makefile Sat Feb 26 20:46:44 2000 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.9 1998/10/26 20:01:03 davem Exp $ +# $Id: Makefile,v 1.10 2000/02/23 08:17:46 jj Exp $ # Makefile for the Sparc boot stuff. # # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -22,16 +22,20 @@ clean: rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s -BTOBJS := $(HEAD) init/main.o init/version.o \ - $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \ - $(NETWORKS) $(DRIVERS) +BTOBJS := $(HEAD) init/main.o init/version.o +BTLIBS := $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \ + $(DRIVERS) $(NETWORKS) # I wanted to make this depend upon BTOBJS so that a parallel # build would work, but this fails because $(HEAD) cannot work # properly as it will cause head.o to be built with the implicit # rules not the ones in kernel/Makefile. Someone please fix. --DaveM vmlinux.o: dummy - $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) $(LIBS) -o vmlinux.o + $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) \ + --start-group \ + $(patsubst %,$(TOPDIR)/%,$(BTLIBS)) \ + $(LIBS) \ + --end-group -o vmlinux.o btfix.s: btfixupprep vmlinux.o $(OBJDUMP) -x vmlinux.o | ./btfixupprep > btfix.s diff -u --recursive --new-file v2.3.47/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c --- v2.3.47/linux/arch/sparc/kernel/ioport.c Sun Feb 20 21:12:38 2000 +++ linux/arch/sparc/kernel/ioport.c Sat Feb 26 20:33:02 2000 @@ -695,42 +695,6 @@ return p-buf; } -static struct proc_dir_entry _sparc_iomap_proc_entry = { - 0, /* Inode number - dynamic */ - 6, /* Length of the file name */ - "io_map", /* The file name */ - S_IFREG | S_IRUGO, /* File mode */ - 1, /* Number of links */ - 0, 0, /* The uid and gid for the file */ - 0, /* The size of the file reported by ls. */ - NULL, /* struct inode_operations * ops */ - NULL, /* get_info: backward compatibility */ - NULL, /* owner */ - NULL, NULL, NULL, /* linkage */ - &sparc_iomap, - _sparc_io_get_info, /* The read function for this file */ - NULL, - /* and more stuff */ -}; - -static struct proc_dir_entry _sparc_dvma_proc_entry = { - 0, /* Inode number - dynamic */ - 8, /* Length of the file name */ - "dvma_map", /* The file name */ - S_IFREG | S_IRUGO, /* File mode */ - 1, /* Number of links */ - 0, 0, /* The uid and gid for the file */ - 0, /* The size of the file reported by ls. */ - NULL, /* struct inode_operations * ops */ - NULL, /* get_info: backward compatibility */ - NULL, /* owner */ - NULL, NULL, NULL, /* linkage */ - &_sparc_dvma, - _sparc_io_get_info, - NULL, - /* some more stuff */ -}; - #endif CONFIG_PROC_FS /* @@ -782,7 +746,7 @@ }; #ifdef CONFIG_PROC_FS - proc_register(&proc_root, &_sparc_iomap_proc_entry); - proc_register(&proc_root, &_sparc_dvma_proc_entry); + create_proc_read_entry("io_map",0,0,_sparc_io_get_info,&sparc_iomap); + create_proc_read_entry("dvma_map",0,0,_sparc_io_get_info,&_sparc_dvma); #endif } diff -u --recursive --new-file v2.3.47/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.3.47/linux/arch/sparc/kernel/irq.c Thu Feb 10 17:11:05 2000 +++ linux/arch/sparc/kernel/irq.c Sat Feb 26 20:46:44 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.101 2000/02/09 11:15:03 davem Exp $ +/* $Id: irq.c,v 1.102 2000/02/25 05:44:35 davem Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -712,4 +712,9 @@ break; } btfixup(); +} + +void init_irq_proc(void) +{ + /* For now, nothing... */ } diff -u --recursive --new-file v2.3.47/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v2.3.47/linux/arch/sparc/kernel/setup.c Tue Feb 1 01:35:43 2000 +++ linux/arch/sparc/kernel/setup.c Sat Feb 26 20:46:44 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.114 2000/01/29 01:08:57 anton Exp $ +/* $Id: setup.c,v 1.115 2000/02/26 04:24:31 davem Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -294,6 +294,8 @@ "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0 }; +extern void paging_init(void); + void __init setup_arch(char **cmdline_p) { int i; @@ -478,6 +480,8 @@ if (serial_console) conswitchp = NULL; + + paging_init(); } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) diff -u --recursive --new-file v2.3.47/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.3.47/linux/arch/sparc/kernel/sparc_ksyms.c Sun Feb 20 21:12:38 2000 +++ linux/arch/sparc/kernel/sparc_ksyms.c Sat Feb 26 20:46:44 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.91 2000/02/18 20:23:24 davem Exp $ +/* $Id: sparc_ksyms.c,v 1.93 2000/02/26 11:02:45 anton Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -92,7 +92,6 @@ /* used by various drivers */ EXPORT_SYMBOL(sparc_cpu_model); -EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor); EXPORT_SYMBOL(kernel_thread); #ifdef SPIN_LOCK_DEBUG EXPORT_SYMBOL(_do_spin_lock); @@ -246,7 +245,6 @@ EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strspn); /* Special internal versions of library functions. */ EXPORT_SYMBOL(__copy_1page); diff -u --recursive --new-file v2.3.47/linux/arch/sparc/lib/locks.S linux/arch/sparc/lib/locks.S --- v2.3.47/linux/arch/sparc/lib/locks.S Tue Oct 27 09:52:20 1998 +++ linux/arch/sparc/lib/locks.S Sat Feb 26 20:46:44 2000 @@ -1,4 +1,4 @@ -/* $Id: locks.S,v 1.15 1998/10/14 09:18:55 jj Exp $ +/* $Id: locks.S,v 1.16 2000/02/26 11:02:47 anton Exp $ * locks.S: SMP low-level lock primitives on Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -14,25 +14,6 @@ .text .align 4 - - /* This is called when the initial acquisition attempt of a spin - * lock fails. The calling convention is weird, return address - * is in %o7 as usual but we agree with the caller to only touch - * and use %g2 as a temporary. We are passed a ptr to the lock - * itself in %g1, %g4 must be restored into %o7 when we return, - * and the caller wants us to return to him at three instructions - * previous to the call instruction which got us here. See how - * this is used in asm/spinlock.h if what I just said confuses - * you to no end. - */ - .globl ___spinlock_waitfor -___spinlock_waitfor: -1: orcc %g2, 0x0, %g0 - bne,a 1b - ldub [%g1], %g2 - ldstub [%g1], %g2 - jmpl %o7 - 12, %g0 - mov %g4, %o7 /* Read/writer locks, as usual this is overly clever to make it * as fast as possible. diff -u --recursive --new-file v2.3.47/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v2.3.47/linux/arch/sparc/mm/init.c Thu Feb 10 17:11:05 2000 +++ linux/arch/sparc/mm/init.c Sat Feb 26 20:46:44 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.80 2000/02/09 21:11:06 davem Exp $ +/* $Id: init.c,v 1.81 2000/02/26 11:59:31 anton Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -40,7 +40,7 @@ struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; unsigned long sparc_unmapped_base; -struct pgtable_cache_struct pgt_quicklists; +struct pgtable_cache_struct pgt_quicklists = { 0, 0, 0, 0, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED }; /* References to section boundaries */ extern char __init_begin, __init_end, _start, end, etext , edata; diff -u --recursive --new-file v2.3.47/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.3.47/linux/arch/sparc64/defconfig Sun Feb 20 21:12:38 2000 +++ linux/arch/sparc64/defconfig Sat Feb 26 20:46:44 2000 @@ -273,9 +273,9 @@ CONFIG_SUNQE=m CONFIG_DE4X5=m CONFIG_VORTEX=m -CONFIG_RTL8139=m +CONFIG_8139TOO=m CONFIG_NE2K_PCI=m -CONFIG_EEXPRESS_PRO100=m +CONFIG_EEPRO100=m CONFIG_ADAPTEC_STARFIRE=m # @@ -299,7 +299,7 @@ # CONFIG_VIDEO_BT848 is not set # -# Filesystems +# File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=m diff -u --recursive --new-file v2.3.47/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.3.47/linux/arch/sparc64/kernel/irq.c Sat Feb 12 11:22:10 2000 +++ linux/arch/sparc64/kernel/irq.c Sat Feb 26 20:46:44 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.83 2000/02/11 06:57:17 jj Exp $ +/* $Id: irq.c,v 1.84 2000/02/25 05:44:41 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -1155,4 +1155,9 @@ : /* No outputs */ : "i" (PSTATE_IE) : "g1"); +} + +void init_irq_proc(void) +{ + /* For now, nothing... */ } diff -u --recursive --new-file v2.3.47/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.3.47/linux/arch/sparc64/kernel/setup.c Wed Dec 29 13:13:14 1999 +++ linux/arch/sparc64/kernel/setup.c Sat Feb 26 20:46:44 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.50 1999/12/01 10:44:45 davem Exp $ +/* $Id: setup.c,v 1.51 2000/02/26 04:24:32 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -451,6 +451,8 @@ "' linux-.soft2 to .soft2"); } +extern void paging_init(void); + void __init setup_arch(char **cmdline_p) { extern int serial_console; /* in console.c, of course */ @@ -587,6 +589,8 @@ #endif if (serial_console) conswitchp = NULL; + + paging_init(); } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) diff -u --recursive --new-file v2.3.47/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.3.47/linux/arch/sparc64/kernel/signal32.c Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc64/kernel/signal32.c Sat Feb 26 20:46:44 2000 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.59 2000/01/21 11:38:52 jj Exp $ +/* $Id: signal32.c,v 1.60 2000/02/25 06:02:37 jj Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -126,6 +126,8 @@ err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_uid, &to->si_uid); break; + case SIGURG: + case SIGIO: case SIGSEGV: case SIGILL: case SIGFPE: diff -u --recursive --new-file v2.3.47/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.3.47/linux/arch/sparc64/kernel/sparc64_ksyms.c Thu Feb 10 17:11:06 2000 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Feb 21 16:32:27 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.74 2000/02/09 11:15:07 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.75 2000/02/21 15:50:08 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -261,7 +261,6 @@ EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strspn); #ifdef CONFIG_SOLARIS_EMUL_MODULE EXPORT_SYMBOL(getname32); diff -u --recursive --new-file v2.3.47/linux/arch/sparc64/lib/VIScsum.S linux/arch/sparc64/lib/VIScsum.S --- v2.3.47/linux/arch/sparc64/lib/VIScsum.S Mon Aug 2 22:07:16 1999 +++ linux/arch/sparc64/lib/VIScsum.S Mon Feb 21 16:32:27 2000 @@ -1,14 +1,15 @@ -/* $Id: VIScsum.S,v 1.5 1999/07/30 09:35:36 davem Exp $ +/* $Id: VIScsum.S,v 1.6 2000/02/20 23:21:39 davem Exp $ * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc * Visual Instruction Set. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 2000 David S. Miller (davem@redhat.com) * * Based on older sparc32/sparc64 checksum.S, which is: * * Copyright(C) 1995 Linus Torvalds * Copyright(C) 1995 Miguel de Icaza - * Copyright(C) 1996,1997 David S. Miller + * Copyright(C) 1996, 1997 David S. Miller * derived from: * Linux/Alpha checksum c-code * Linux/ix86 inline checksum assembly @@ -38,290 +39,290 @@ * tricks are UltraLinux trade secrets :)) */ -#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10) \ - fcmpgt32 %fz, %f0, %g1 /* FPM Group */; \ - fcmpgt32 %fz, %f2, %g2 /* FPM Group */; \ - fcmpgt32 %fz, %f4, %g3 /* FPM Group */; \ - fcmpgt32 %fz, %f6, %g5 /* FPM Group */; \ - inc %g1 /* IEU0 */; \ - fcmpgt32 %fz, %f8, %g7 /* FPM Group */; \ - srl %g1, 1, %g1 /* IEU0 */; \ - inc %g2 /* IEU1 */; \ - fcmpgt32 %fz, %f10, %o3 /* FPM Group */; \ - srl %g2, 1, %g2 /* IEU0 */; \ - add %o2, %g1, %o2 /* IEU1 */; \ - add %g3, 1, %g3 /* IEU0 Group */; \ - srl %g3, 1, %g3 /* IEU0 Group */; \ - add %o2, %g2, %o2 /* IEU1 */; \ - inc %g5 /* IEU0 Group */; \ - add %o2, %g3, %o2 /* IEU1 */; +#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10) \ + fcmpgt32 %fz, %f0, %g1 /* FPM Group */; \ + fcmpgt32 %fz, %f2, %g2 /* FPM Group */; \ + fcmpgt32 %fz, %f4, %g3 /* FPM Group */; \ + inc %g1 /* IEU0 Group */; \ + fcmpgt32 %fz, %f6, %g5 /* FPM */; \ + srl %g1, 1, %g1 /* IEU0 Group */; \ + fcmpgt32 %fz, %f8, %g7 /* FPM */; \ + inc %g2 /* IEU0 Group */; \ + fcmpgt32 %fz, %f10, %o3 /* FPM */; \ + srl %g2, 1, %g2 /* IEU0 Group */; \ + inc %g3 /* IEU1 */; \ + srl %g3, 1, %g3 /* IEU0 Group */; \ + add %o2, %g1, %o2 /* IEU1 */; \ + add %o2, %g2, %o2 /* IEU0 Group */; \ + inc %g5 /* IEU1 */; \ + add %o2, %g3, %o2 /* IEU0 Group */; -#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14) \ - fcmpgt32 %O12, %f12, %o4 /* FPM Group */; \ - srl %g5, 1, %g5 /* IEU0 */; \ - inc %g7 /* IEU1 */; \ - fpadd32 %F0, %f0, %F0 /* FPA */; \ - fcmpgt32 %O14, %f14, %o5 /* FPM Group */; \ - srl %g7, 1, %g7 /* IEU0 */; \ - add %o2, %g5, %o2 /* IEU1 */; \ - fpadd32 %F2, %f2, %F2 /* FPA */; \ - inc %o3 /* IEU0 Group */; \ - add %o2, %g7, %o2 /* IEU1 */; \ - fcmpgt32 %f0, %F0, %g1 /* FPM Group */; \ - srl %o3, 1, %o3 /* IEU0 */; \ - inc %o4 /* IEU1 */; \ - fpadd32 %F4, %f4, %F4 /* FPA */; \ - fcmpgt32 %f2, %F2, %g2 /* FPM Group */; \ - srl %o4, 1, %o4 /* IEU0 */; \ - add %o2, %o3, %o2 /* IEU1 */; \ - fpadd32 %F6, %f6, %F6 /* FPA */; \ - inc %o5 /* IEU0 Group */; \ - add %o2, %o4, %o2 /* IEU1 */; \ - fcmpgt32 %f4, %F4, %g3 /* FPM Group */; \ - srl %o5, 1, %o5 /* IEU0 */; \ - inc %g1 /* IEU1 */; \ - fpadd32 %F8, %f8, %F8 /* FPA */; \ - fcmpgt32 %f6, %F6, %g5 /* FPM Group */; \ - srl %g1, 1, %g1 /* IEU0 */; \ - add %o2, %o5, %o2 /* IEU1 */; \ - fpadd32 %F10, %f10, %F10 /* FPA */; \ - inc %g2 /* IEU0 Group */; \ - add %o2, %g1, %o2 /* IEU1 */; \ - fcmpgt32 %f8, %F8, %g7 /* FPM Group */; \ - srl %g2, 1, %g2 /* IEU0 */; \ - inc %g3 /* IEU1 */; \ - fpadd32 %F12, %f12, %F12 /* FPA */; \ - fcmpgt32 %f10, %F10, %o3 /* FPM Group */; \ - srl %g3, 1, %g3 /* IEU0 */; \ - add %o2, %g2, %o2 /* IEU1 */; \ - fpadd32 %F14, %f14, %F14 /* FPA */; \ - inc %g5 /* IEU0 Group */; \ - add %o2, %g3, %o2 /* IEU1 */; +#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14) \ + srl %g5, 1, %g5 /* IEU0 Group */; \ + fpadd32 %F0, %f0, %F0 /* FPA */; \ + fcmpgt32 %O12, %f12, %o4 /* FPM */; \ + inc %g7 /* IEU0 Group */; \ + fpadd32 %F2, %f2, %F2 /* FPA */; \ + fcmpgt32 %O14, %f14, %o5 /* FPM */; \ + add %o2, %g5, %o2 /* IEU1 Group */; \ + fpadd32 %F4, %f4, %F4 /* FPA */; \ + fcmpgt32 %f0, %F0, %g1 /* FPM */; \ + srl %g7, 1, %g7 /* IEU0 Group */; \ + fpadd32 %F6, %f6, %F6 /* FPA */; \ + fcmpgt32 %f2, %F2, %g2 /* FPM */; \ + add %o2, %g7, %o2 /* IEU0 Group */; \ + fpadd32 %F8, %f8, %F8 /* FPA */; \ + fcmpgt32 %f4, %F4, %g3 /* FPM */; \ + inc %o3 /* IEU0 Group */; \ + fpadd32 %F10, %f10, %F10 /* FPA */; \ + fcmpgt32 %f6, %F6, %g5 /* FPM */; \ + srl %o3, 1, %o3 /* IEU0 Group */; \ + fpadd32 %F12, %f12, %F12 /* FPA */; \ + fcmpgt32 %f8, %F8, %g7 /* FPM */; \ + add %o2, %o3, %o2 /* IEU0 Group */; \ + fpadd32 %F14, %f14, %F14 /* FPA */; \ + fcmpgt32 %f10, %F10, %o3 /* FPM */; \ + inc %o4 /* IEU0 Group */; \ + inc %o5 /* IEU1 */; \ + srl %o4, 1, %o4 /* IEU0 Group */; \ + inc %g1 /* IEU1 */; \ + srl %o5, 1, %o5 /* IEU0 Group */; \ + add %o2, %o4, %o2 /* IEU1 */; \ + srl %g1, 1, %g1 /* IEU0 Group */; \ + add %o2, %o5, %o2 /* IEU1 */; \ + inc %g2 /* IEU0 Group */; \ + add %o2, %g1, %o2 /* IEU1 */; \ + srl %g2, 1, %g2 /* IEU0 Group */; \ + inc %g3 /* IEU1 */; \ + srl %g3, 1, %g3 /* IEU0 Group */; \ + add %o2, %g2, %o2 /* IEU1 */; \ + inc %g5 /* IEU0 Group */; \ + add %o2, %g3, %o2 /* IEU0 */; -#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz) \ - fcmpgt32 %O12, %f12, %o4 /* FPM Group */; \ - srl %g5, 1, %g5 /* IEU0 */; \ - inc %g7 /* IEU1 */; \ - fpadd32 %f2, %f0, %S0 /* FPA */; \ - fcmpgt32 %O14, %f14, %o5 /* FPM Group */; \ - srl %g7, 1, %g7 /* IEU0 */; \ - add %o2, %g5, %o2 /* IEU1 */; \ - fpadd32 %f6, %f4, %S1 /* FPA */; \ - inc %o3 /* IEU0 Group */; \ - add %o2, %g7, %o2 /* IEU1 */; \ - fcmpgt32 %f0, %S0, %g1 /* FPM Group */; \ - srl %o3, 1, %o3 /* IEU0 */; \ - inc %o4 /* IEU1 */; \ - fpadd32 %f10, %f8, %S2 /* FPA */; \ - fcmpgt32 %f4, %S1, %g2 /* FPM Group */; \ - srl %o4, 1, %o4 /* IEU0 */; \ - add %o2, %o3, %o2 /* IEU1 */; \ - fpadd32 %f14, %f12, %S3 /* FPA */; \ - inc %o5 /* IEU0 Group */; \ - add %o2, %o4, %o2 /* IEU1 */; \ - fzero %fz /* FPA */; \ - fcmpgt32 %f8, %S2, %g3 /* FPM Group */; \ - srl %o5, 1, %o5 /* IEU0 */; \ - inc %g1 /* IEU1 */; \ - fpadd32 %S0, %S1, %T0 /* FPA */; \ - fcmpgt32 %f12, %S3, %g5 /* FPM Group */; \ - srl %g1, 1, %g1 /* IEU0 */; \ - add %o2, %o5, %o2 /* IEU1 */; \ - fpadd32 %S2, %S3, %T1 /* FPA */; \ - inc %g2 /* IEU0 Group */; \ - add %o2, %g1, %o2 /* IEU1 */; \ - fcmpgt32 %S0, %T0, %g7 /* FPM Group */; \ - srl %g2, 1, %g2 /* IEU0 */; \ - inc %g3 /* IEU1 */; \ - fcmpgt32 %S2, %T1, %o3 /* FPM Group */; \ - srl %g3, 1, %g3 /* IEU0 */; \ - add %o2, %g2, %o2 /* IEU1 */; \ - inc %g5 /* IEU0 Group */; \ - add %o2, %g3, %o2 /* IEU1 */; \ - fcmpgt32 %fz, %f2, %o4 /* FPM Group */; \ - srl %g5, 1, %g5 /* IEU0 */; \ - inc %g7 /* IEU1 */; \ - fpadd32 %T0, %T1, %U0 /* FPA */; \ - fcmpgt32 %fz, %f6, %o5 /* FPM Group */; \ - srl %g7, 1, %g7 /* IEU0 */; \ - add %o2, %g5, %o2 /* IEU1 */; \ - inc %o3 /* IEU0 Group */; \ - add %o2, %g7, %o2 /* IEU1 */; \ - fcmpgt32 %fz, %f10, %g1 /* FPM Group */; \ - srl %o3, 1, %o3 /* IEU0 */; \ - inc %o4 /* IEU1 */; \ - fcmpgt32 %fz, %f14, %g2 /* FPM Group */; \ - srl %o4, 1, %o4 /* IEU0 */; \ - add %o2, %o3, %o2 /* IEU1 */; \ - std %U0, [%sp + STACKOFF] /* Store Group */; \ - inc %o5 /* IEU0 */; \ - sub %o2, %o4, %o2 /* IEU1 */; \ - fcmpgt32 %fz, %S1, %g3 /* FPM Group */; \ - srl %o5, 1, %o5 /* IEU0 */; \ - inc %g1 /* IEU1 */; \ - fcmpgt32 %fz, %S3, %g5 /* FPM Group */; \ - srl %g1, 1, %g1 /* IEU0 */; \ - sub %o2, %o5, %o2 /* IEU1 */; \ - ldx [%sp + STACKOFF], %o5 /* Load Group */; \ - inc %g2 /* IEU0 */; \ - sub %o2, %g1, %o2 /* IEU1 */; \ - fcmpgt32 %fz, %T1, %g7 /* FPM Group */; \ - srl %g2, 1, %g2 /* IEU0 */; \ - inc %g3 /* IEU1 */; \ - fcmpgt32 %T0, %U0, %o3 /* FPM Group */; \ - srl %g3, 1, %g3 /* IEU0 */; \ - sub %o2, %g2, %o2 /* IEU1 */; \ - inc %g5 /* IEU0 Group */; \ - sub %o2, %g3, %o2 /* IEU1 */; \ - fcmpgt32 %fz, %U0, %o4 /* FPM Group */; \ - srl %g5, 1, %g5 /* IEU0 */; \ - inc %g7 /* IEU1 */; \ - srl %g7, 1, %g7 /* IEU0 Group */; \ - sub %o2, %g5, %o2 /* IEU1 */; \ - inc %o3 /* IEU0 Group */; \ - sub %o2, %g7, %o2 /* IEU1 */; \ - srl %o3, 1, %o3 /* IEU0 Group */; \ - inc %o4 /* IEU1 */; \ - srl %o4, 1, %o4 /* IEU0 Group */; \ - add %o2, %o3, %o2 /* IEU1 */; \ - sub %o2, %o4, %o2 /* IEU0 Group */; \ - addcc %o2, %o5, %o2 /* IEU1 Group */; \ - bcs,a,pn %xcc, 33f /* CTI */; \ - add %o2, 1, %o2 /* IEU0 */; \ -33: /* That's it */; +#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz) \ + srl %g5, 1, %g5 /* IEU0 Group */; \ + fpadd32 %f2, %f0, %S0 /* FPA */; \ + fcmpgt32 %O12, %f12, %o4 /* FPM */; \ + inc %g7 /* IEU0 Group */; \ + fpadd32 %f6, %f4, %S1 /* FPA */; \ + fcmpgt32 %O14, %f14, %o5 /* FPM */; \ + srl %g7, 1, %g7 /* IEU0 Group */; \ + fpadd32 %f10, %f8, %S2 /* FPA */; \ + fcmpgt32 %f0, %S0, %g1 /* FPM */; \ + inc %o3 /* IEU0 Group */; \ + fpadd32 %f14, %f12, %S3 /* FPA */; \ + fcmpgt32 %f4, %S1, %g2 /* FPM */; \ + add %o2, %g5, %o2 /* IEU0 Group */; \ + fpadd32 %S0, %S1, %T0 /* FPA */; \ + fcmpgt32 %f8, %S2, %g3 /* FPM */; \ + add %o2, %g7, %o2 /* IEU0 Group */; \ + fzero %fz /* FPA */; \ + fcmpgt32 %f12, %S3, %g5 /* FPM */; \ + srl %o3, 1, %o3 /* IEU0 Group */; \ + fpadd32 %S2, %S3, %T1 /* FPA */; \ + fcmpgt32 %S0, %T0, %g7 /* FPM */; \ + add %o2, %o3, %o2 /* IEU0 Group */; \ + fpadd32 %T0, %T1, %U0 /* FPA */; \ + fcmpgt32 %S2, %T1, %o3 /* FPM */; \ + inc %o4 /* IEU0 Group */; \ + inc %o5 /* IEU1 */; \ + srl %o4, 1, %o4 /* IEU0 Group */; \ + inc %g1 /* IEU1 */; \ + add %o2, %o4, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %f2, %o4 /* FPM */; \ + srl %o5, 1, %o5 /* IEU0 Group */; \ + inc %g2 /* IEU1 */; \ + add %o2, %o5, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %f6, %o5 /* FPM */; \ + srl %g1, 1, %g1 /* IEU0 Group */; \ + inc %g3 /* IEU1 */; \ + add %o2, %g1, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %f10, %g1 /* FPM */; \ + srl %g2, 1, %g2 /* IEU0 Group */; \ + inc %g5 /* IEU1 */; \ + add %o2, %g2, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %f14, %g2 /* FPM */; \ + srl %g3, 1, %g3 /* IEU0 Group */; \ + inc %g7 /* IEU1 */; \ + add %o2, %g3, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %S1, %g3 /* FPM */; \ + srl %g5, 1, %g5 /* IEU0 Group */; \ + inc %o3 /* IEU1 */; \ + add %o2, %g5, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %S3, %g5 /* FPM */; \ + srl %g7, 1, %g7 /* IEU0 Group */; \ + inc %o4 /* IEU1 */; \ + add %o2, %g7, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %T1, %g7 /* FPM */; \ + srl %o3, 1, %o3 /* IEU0 Group */; \ + inc %o5 /* IEU1 */; \ + add %o2, %o3, %o2 /* IEU0 Group */; \ + fcmpgt32 %T0, %U0, %o3 /* FPM */; \ + srl %o4, 1, %o4 /* IEU0 Group */; \ + inc %g1 /* IEU1 */; \ + sub %o2, %o4, %o2 /* IEU0 Group */; \ + fcmpgt32 %fz, %U0, %o4 /* FPM */; \ + srl %o5, 1, %o5 /* IEU0 Group */; \ + inc %g2 /* IEU1 */; \ + srl %g1, 1, %g1 /* IEU0 Group */; \ + sub %o2, %o5, %o2 /* IEU1 */; \ + std %U0, [%sp + STACKOFF] /* Store */; \ + srl %g2, 1, %g2 /* IEU0 Group */; \ + sub %o2, %g1, %o2 /* IEU1 */; \ + inc %g3 /* IEU0 Group */; \ + sub %o2, %g2, %o2 /* IEU1 */; \ + srl %g3, 1, %g3 /* IEU0 Group */; \ + inc %g5 /* IEU1 */; \ + srl %g5, 1, %g5 /* IEU0 Group */; \ + sub %o2, %g3, %o2 /* IEU1 */; \ + ldx [%sp + STACKOFF], %o5 /* Load Group */; \ + inc %g7 /* IEU0 */; \ + sub %o2, %g5, %o2 /* IEU1 */; \ + srl %g7, 1, %g7 /* IEU0 Group */; \ + inc %o3 /* IEU1 */; \ + srl %o3, 1, %o3 /* IEU0 Group */; \ + sub %o2, %g7, %o2 /* IEU1 */; \ + inc %o4 /* IEU0 Group */; \ + add %o2, %o3, %o2 /* IEU1 */; \ + srl %o4, 1, %o4 /* IEU0 Group */; \ + sub %o2, %o4, %o2 /* IEU0 Group */; \ + addcc %o2, %o5, %o2 /* IEU1 Group */; \ + bcs,a,pn %xcc, 33f /* CTI */; \ + add %o2, 1, %o2 /* IEU0 */; \ +33: /* That's it */; -#define CSUM_LASTCHUNK(offset) \ - ldx [%o0 - offset - 0x10], %g2; \ - ldx [%o0 - offset - 0x08], %g3; \ - addcc %g2, %o2, %o2; \ - bcs,a,pn %xcc, 31f; \ - add %o2, 1, %o2; \ -31: addcc %g3, %o2, %o2; \ - bcs,a,pn %xcc, 32f; \ - add %o2, 1, %o2; \ +#define CSUM_LASTCHUNK(offset) \ + ldx [%o0 - offset - 0x10], %g2; \ + ldx [%o0 - offset - 0x08], %g3; \ + addcc %g2, %o2, %o2; \ + bcs,a,pn %xcc, 31f; \ + add %o2, 1, %o2; \ +31: addcc %g3, %o2, %o2; \ + bcs,a,pn %xcc, 32f; \ + add %o2, 1, %o2; \ 32: .text .globl csum_partial .align 32 csum_partial: - andcc %o0, 7, %g0 /* IEU1 Group */ - be,pt %icc, 4f /* CTI */ - andcc %o0, 0x38, %g3 /* IEU1 */ - mov 1, %g5 /* IEU0 Group */ - cmp %o1, 6 /* IEU1 */ - bl,pn %icc, 21f /* CTI */ - andcc %o0, 2, %g0 /* IEU1 Group */ - be,pt %icc, 1f /* CTI */ - and %o0, 4, %g7 /* IEU0 */ - lduh [%o0], %g2 /* Load */ - sub %o1, 2, %o1 /* IEU0 Group */ - add %o0, 2, %o0 /* IEU1 */ - andcc %o0, 4, %g7 /* IEU1 Group */ - sll %g5, 16, %g5 /* IEU0 */ - sll %g2, 16, %g2 /* IEU0 Group */ - addcc %g2, %o2, %o2 /* IEU1 Group (regdep) */ - bcs,a,pn %icc, 1f /* CTI */ - add %o2, %g5, %o2 /* IEU0 */ -1: ld [%o0], %g2 /* Load */ - brz,a,pn %g7, 4f /* CTI+IEU1 Group */ - and %o0, 0x38, %g3 /* IEU0 */ - add %o0, 4, %o0 /* IEU0 Group */ - sub %o1, 4, %o1 /* IEU1 */ - addcc %g2, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %icc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: and %o0, 0x38, %g3 /* IEU1 Group */ -4: srl %o2, 0, %o2 /* IEU0 Group */ - mov 0x40, %g1 /* IEU1 */ - brz,pn %g3, 3f /* CTI+IEU1 Group */ - sub %g1, %g3, %g1 /* IEU0 */ - cmp %o1, 56 /* IEU1 Group */ - blu,pn %icc, 20f /* CTI */ - andcc %o0, 8, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - ldx [%o0], %g2 /* Load */ - add %o0, 8, %o0 /* IEU0 Group */ - sub %o1, 8, %o1 /* IEU1 */ - addcc %g2, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: andcc %g1, 0x10, %g0 /* IEU1 Group */ - be,pn %icc, 2f /* CTI */ - and %g1, 0x20, %g1 /* IEU0 */ - ldx [%o0], %g2 /* Load */ - ldx [%o0+8], %g3 /* Load Group */ - add %o0, 16, %o0 /* IEU0 */ - sub %o1, 16, %o1 /* IEU1 */ - addcc %g2, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: addcc %g3, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 2f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -2: brz,pn %g1, 3f /* CTI+IEU1 Group */ - ldx [%o0], %g2 /* Load */ - ldx [%o0+8], %g3 /* Load Group */ - ldx [%o0+16], %g5 /* Load Group */ - ldx [%o0+24], %g7 /* Load Group */ - add %o0, 32, %o0 /* IEU0 */ - sub %o1, 32, %o1 /* IEU1 */ - addcc %g2, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: addcc %g3, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: addcc %g5, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: addcc %g7, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 3f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -3: cmp %o1, 0xc0 /* IEU1 Group */ - blu,pn %icc, 20f /* CTI */ - sllx %o2, 32, %g5 /* IEU0 */ + andcc %o0, 7, %g0 /* IEU1 Group */ + be,pt %icc, 4f /* CTI */ + andcc %o0, 0x38, %g3 /* IEU1 */ + mov 1, %g5 /* IEU0 Group */ + cmp %o1, 6 /* IEU1 */ + bl,pn %icc, 21f /* CTI */ + andcc %o0, 2, %g0 /* IEU1 Group */ + be,pt %icc, 1f /* CTI */ + and %o0, 4, %g7 /* IEU0 */ + lduh [%o0], %g2 /* Load */ + sub %o1, 2, %o1 /* IEU0 Group */ + add %o0, 2, %o0 /* IEU1 */ + andcc %o0, 4, %g7 /* IEU1 Group */ + sll %g5, 16, %g5 /* IEU0 */ + sll %g2, 16, %g2 /* IEU0 Group */ + addcc %g2, %o2, %o2 /* IEU1 Group (regdep) */ + bcs,a,pn %icc, 1f /* CTI */ + add %o2, %g5, %o2 /* IEU0 */ +1: ld [%o0], %g2 /* Load */ + brz,a,pn %g7, 4f /* CTI+IEU1 Group */ + and %o0, 0x38, %g3 /* IEU0 */ + add %o0, 4, %o0 /* IEU0 Group */ + sub %o1, 4, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: and %o0, 0x38, %g3 /* IEU1 Group */ +4: srl %o2, 0, %o2 /* IEU0 Group */ + mov 0x40, %g1 /* IEU1 */ + brz,pn %g3, 3f /* CTI+IEU1 Group */ + sub %g1, %g3, %g1 /* IEU0 */ + cmp %o1, 56 /* IEU1 Group */ + blu,pn %icc, 20f /* CTI */ + andcc %o0, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + ldx [%o0], %g2 /* Load */ + add %o0, 8, %o0 /* IEU0 Group */ + sub %o1, 8, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: andcc %g1, 0x10, %g0 /* IEU1 Group */ + be,pn %icc, 2f /* CTI */ + and %g1, 0x20, %g1 /* IEU0 */ + ldx [%o0], %g2 /* Load */ + ldx [%o0+8], %g3 /* Load Group */ + add %o0, 16, %o0 /* IEU0 */ + sub %o1, 16, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g3, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 2f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +2: brz,pn %g1, 3f /* CTI+IEU1 Group */ + ldx [%o0], %g2 /* Load */ + ldx [%o0+8], %g3 /* Load Group */ + ldx [%o0+16], %g5 /* Load Group */ + ldx [%o0+24], %g7 /* Load Group */ + add %o0, 32, %o0 /* IEU0 */ + sub %o1, 32, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g3, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g5, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g7, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 3f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +3: cmp %o1, 0xc0 /* IEU1 Group */ + blu,pn %icc, 20f /* CTI */ + sllx %o2, 32, %g5 /* IEU0 */ #ifdef __KERNEL__ VISEntry #endif - addcc %o2, %g5, %o2 /* IEU1 Group */ - sub %o1, 0xc0, %o1 /* IEU0 */ - wr %g0, ASI_BLK_P, %asi /* LSU Group */ - membar #StoreLoad /* LSU Group */ - srlx %o2, 32, %o2 /* IEU0 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU1 */ -1: andcc %o1, 0x80, %g0 /* IEU1 Group */ - bne,pn %icc, 7f /* CTI */ - andcc %o1, 0x40, %g0 /* IEU1 Group */ - be,pn %icc, 6f /* CTI */ - fzero %f12 /* FPA */ - fzero %f14 /* FPA Group */ + addcc %o2, %g5, %o2 /* IEU1 Group */ + sub %o1, 0xc0, %o1 /* IEU0 */ + wr %g0, ASI_BLK_P, %asi /* LSU Group */ + membar #StoreLoad /* LSU Group */ + srlx %o2, 32, %o2 /* IEU0 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU1 */ +1: andcc %o1, 0x80, %g0 /* IEU1 Group */ + bne,pn %icc, 7f /* CTI */ + andcc %o1, 0x40, %g0 /* IEU1 Group */ + be,pn %icc, 6f /* CTI */ + fzero %f12 /* FPA */ + fzero %f14 /* FPA Group */ ldda [%o0 + 0x000] %asi, %f16 ldda [%o0 + 0x040] %asi, %f32 ldda [%o0 + 0x080] %asi, %f48 START_THE_TRICK(f12,f16,f18,f20,f22,f24,f26) ba,a,pt %xcc, 3f -6: sub %o0, 0x40, %o0 /* IEU0 Group */ - fzero %f28 /* FPA */ - fzero %f30 /* FPA Group */ +6: sub %o0, 0x40, %o0 /* IEU0 Group */ + fzero %f28 /* FPA */ + fzero %f30 /* FPA Group */ ldda [%o0 + 0x040] %asi, %f32 ldda [%o0 + 0x080] %asi, %f48 ldda [%o0 + 0x0c0] %asi, %f0 START_THE_TRICK(f28,f32,f34,f36,f38,f40,f42) ba,a,pt %xcc, 4f -7: bne,pt %icc, 8f /* CTI */ - fzero %f44 /* FPA */ - add %o0, 0x40, %o0 /* IEU0 Group */ - fzero %f60 /* FPA */ - fzero %f62 /* FPA Group */ +7: bne,pt %icc, 8f /* CTI */ + fzero %f44 /* FPA */ + add %o0, 0x40, %o0 /* IEU0 Group */ + fzero %f60 /* FPA */ + fzero %f62 /* FPA Group */ ldda [%o0 - 0x040] %asi, %f0 ldda [%o0 + 0x000] %asi, %f16 ldda [%o0 + 0x040] %asi, %f32 START_THE_TRICK(f60,f0,f2,f4,f6,f8,f10) ba,a,pt %xcc, 2f -8: add %o0, 0x80, %o0 /* IEU0 Group */ - fzero %f46 /* FPA */ +8: add %o0, 0x80, %o0 /* IEU0 Group */ + fzero %f46 /* FPA */ ldda [%o0 - 0x080] %asi, %f48 ldda [%o0 - 0x040] %asi, %f0 ldda [%o0 + 0x000] %asi, %f16 @@ -333,36 +334,36 @@ 3: DO_THE_TRICK(f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46) ldda [%o0 + 0x0c0] %asi, %f0 4: DO_THE_TRICK(f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,f48,f50,f52,f54,f56,f58,f60,f62) - add %o0, 0x100, %o0 /* IEU0 Group */ - subcc %o1, 0x100, %o1 /* IEU1 */ - bgeu,a,pt %icc, 1b /* CTI */ + add %o0, 0x100, %o0 /* IEU0 Group */ + subcc %o1, 0x100, %o1 /* IEU1 */ + bgeu,a,pt %icc, 1b /* CTI */ ldda [%o0 + 0x000] %asi, %f16 - membar #Sync /* LSU Group */ + membar #Sync /* LSU Group */ DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14) END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30) #ifdef __KERNEL__ ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %g7 #endif - and %o1, 0x3f, %o1 /* IEU0 Group */ + and %o1, 0x3f, %o1 /* IEU0 Group */ #ifdef __KERNEL__ VISExit wr %g7, %g0, %asi #endif -20: andcc %o1, 0xf0, %g1 /* IEU1 Group */ - be,pn %icc, 23f /* CTI */ - and %o1, 0xf, %o3 /* IEU0 */ +20: andcc %o1, 0xf0, %g1 /* IEU1 Group */ + be,pn %icc, 23f /* CTI */ + and %o1, 0xf, %o3 /* IEU0 */ #ifdef __KERNEL__ -22: sll %g1, 1, %o4 /* IEU0 Group */ - sethi %hi(23f), %g7 /* IEU1 */ - sub %g7, %o4, %g7 /* IEU0 Group */ - jmpl %g7 + %lo(23f), %g0 /* CTI Group brk forced */ - add %o0, %g1, %o0 /* IEU0 */ +22: sll %g1, 1, %o4 /* IEU0 Group */ + sethi %hi(23f), %g7 /* IEU1 */ + sub %g7, %o4, %g7 /* IEU0 Group */ + jmpl %g7 + %lo(23f), %g0 /* CTI Group brk forced*/ + add %o0, %g1, %o0 /* IEU0 */ #else -22: rd %pc, %g7 /* LSU Group+4bubbles */ - sll %g1, 1, %o4 /* IEU0 Group */ - sub %g7, %o4, %g7 /* IEU0 Group (regdep) */ - jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced */ - add %o0, %g1, %o0 /* IEU0 */ +22: rd %pc, %g7 /* LSU Group+4bubbles */ + sll %g1, 1, %o4 /* IEU0 Group */ + sub %g7, %o4, %g7 /* IEU0 Group (regdep) */ + jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced*/ + add %o0, %g1, %o0 /* IEU0 */ #endif CSUM_LASTCHUNK(0xe0) CSUM_LASTCHUNK(0xd0) @@ -379,72 +380,72 @@ CSUM_LASTCHUNK(0x20) CSUM_LASTCHUNK(0x10) CSUM_LASTCHUNK(0x00) -23: brnz,pn %o3, 26f /* CTI+IEU1 Group */ -24: sllx %o2, 32, %g1 /* IEU0 */ -25: addcc %o2, %g1, %o0 /* IEU1 Group */ - srlx %o0, 32, %o0 /* IEU0 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o0, 1, %o0 /* IEU1 */ -1: retl /* CTI Group brk forced */ - srl %o0, 0, %o0 /* IEU0 */ -26: andcc %o1, 8, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - ldx [%o0], %g3 /* Load */ - add %o0, 8, %o0 /* IEU0 Group */ - addcc %g3, %o2, %o2 /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: andcc %o1, 4, %g0 /* IEU1 Group */ - be,a,pn %icc, 1f /* CTI */ - clr %g2 /* IEU0 */ - ld [%o0], %g2 /* Load */ - add %o0, 4, %o0 /* IEU0 Group */ - sllx %g2, 32, %g2 /* IEU0 Group */ -1: andcc %o1, 2, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o4 /* IEU0 Group */ - lduh [%o0], %o4 /* Load */ - add %o0, 2, %o0 /* IEU1 */ - sll %o4, 16, %o4 /* IEU0 Group */ -1: andcc %o1, 1, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o5 /* IEU0 Group */ - ldub [%o0], %o5 /* Load */ - sll %o5, 8, %o5 /* IEU0 Group */ -1: or %g2, %o4, %o4 /* IEU1 */ - or %o5, %o4, %o4 /* IEU0 Group (regdep) */ - addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: ba,pt %xcc, 25b /* CTI Group */ - sllx %o2, 32, %g1 /* IEU0 */ -21: srl %o2, 0, %o2 /* IEU0 Group */ - cmp %o1, 0 /* IEU1 */ - be,pn %icc, 24b /* CTI */ - andcc %o1, 4, %g0 /* IEU1 Group */ - be,a,pn %icc, 1f /* CTI */ - clr %g2 /* IEU0 */ - lduh [%o0], %g3 /* Load */ - lduh [%o0+2], %g2 /* Load Group */ - add %o0, 4, %o0 /* IEU0 Group */ - sllx %g3, 48, %g3 /* IEU0 Group */ - sllx %g2, 32, %g2 /* IEU0 Group */ - or %g3, %g2, %g2 /* IEU0 Group */ -1: andcc %o1, 2, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o4 /* IEU0 Group */ - lduh [%o0], %o4 /* Load */ - add %o0, 2, %o0 /* IEU1 */ - sll %o4, 16, %o4 /* IEU0 Group */ -1: andcc %o1, 1, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o5 /* IEU0 Group */ - ldub [%o0], %o5 /* Load */ - sll %o5, 8, %o5 /* IEU0 Group */ -1: or %g2, %o4, %o4 /* IEU1 */ - or %o5, %o4, %o4 /* IEU0 Group (regdep) */ - addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %o2, 1, %o2 /* IEU0 */ -1: ba,pt %xcc, 25b /* CTI Group */ - sllx %o2, 32, %g1 /* IEU0 */ +23: brnz,pn %o3, 26f /* CTI+IEU1 Group */ +24: sllx %o2, 32, %g1 /* IEU0 */ +25: addcc %o2, %g1, %o0 /* IEU1 Group */ + srlx %o0, 32, %o0 /* IEU0 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o0, 1, %o0 /* IEU1 */ +1: retl /* CTI Group brk forced*/ + srl %o0, 0, %o0 /* IEU0 */ +26: andcc %o1, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + ldx [%o0], %g3 /* Load */ + add %o0, 8, %o0 /* IEU0 Group */ + addcc %g3, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: andcc %o1, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + ld [%o0], %g2 /* Load */ + add %o0, 4, %o0 /* IEU0 Group */ + sllx %g2, 32, %g2 /* IEU0 Group */ +1: andcc %o1, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o4 /* IEU0 Group */ + lduh [%o0], %o4 /* Load */ + add %o0, 2, %o0 /* IEU1 */ + sll %o4, 16, %o4 /* IEU0 Group */ +1: andcc %o1, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + ldub [%o0], %o5 /* Load */ + sll %o5, 8, %o5 /* IEU0 Group */ +1: or %g2, %o4, %o4 /* IEU1 */ + or %o5, %o4, %o4 /* IEU0 Group (regdep) */ + addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %o2, 32, %g1 /* IEU0 */ +21: srl %o2, 0, %o2 /* IEU0 Group */ + cmp %o1, 0 /* IEU1 */ + be,pn %icc, 24b /* CTI */ + andcc %o1, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + lduh [%o0], %g3 /* Load */ + lduh [%o0+2], %g2 /* Load Group */ + add %o0, 4, %o0 /* IEU0 Group */ + sllx %g3, 48, %g3 /* IEU0 Group */ + sllx %g2, 32, %g2 /* IEU0 Group */ + or %g3, %g2, %g2 /* IEU0 Group */ +1: andcc %o1, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o4 /* IEU0 Group */ + lduh [%o0], %o4 /* Load */ + add %o0, 2, %o0 /* IEU1 */ + sll %o4, 16, %o4 /* IEU0 Group */ +1: andcc %o1, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + ldub [%o0], %o5 /* Load */ + sll %o5, 8, %o5 /* IEU0 Group */ +1: or %g2, %o4, %o4 /* IEU1 */ + or %o5, %o4, %o4 /* IEU0 Group (regdep) */ + addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %o2, 32, %g1 /* IEU0 */ diff -u --recursive --new-file v2.3.47/linux/arch/sparc64/lib/VIScsumcopy.S linux/arch/sparc64/lib/VIScsumcopy.S --- v2.3.47/linux/arch/sparc64/lib/VIScsumcopy.S Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc64/lib/VIScsumcopy.S Mon Feb 21 16:32:27 2000 @@ -1,4 +1,4 @@ -/* $Id: VIScsumcopy.S,v 1.7 2000/01/19 04:06:03 davem Exp $ +/* $Id: VIScsumcopy.S,v 1.8 2000/02/20 23:21:39 davem Exp $ * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous * copying utilizing the UltraSparc Visual Instruction Set. * @@ -62,384 +62,386 @@ * per 64bytes checksummed/copied. */ -#define LDBLK(O0) \ - ldda [%src] %asi, %O0 /* Load Group */ +#define LDBLK(O0) \ + ldda [%src] %asi, %O0 /* Load Group */ -#define STBLK \ - stda %f48, [%dst] ASI_BLK_P /* Store */ +#define STBLK \ + stda %f48, [%dst] ASI_BLK_P /* Store */ -#define ST(fx,off) \ - std %fx, [%dst + off] /* Store */ +#define ST(fx,off) \ + std %fx, [%dst + off] /* Store */ -#define SYNC \ +#define SYNC \ membar #Sync #define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DUMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \ - LOAD /* Load Group */; \ - faligndata %A14, %F0, %A14 /* FPA Group */; \ - inc %x5 /* IEU0 */; \ - STORE1 /* Store (optional) */; \ - faligndata %F0, %F2, %A0 /* FPA Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - add %sum, %x4, %sum /* IEU1 */; \ - fpadd32 %F0, %f0, %F0 /* FPA Group */; \ - inc %x6 /* IEU0 */; \ - STORE2 /* Store (optional) */; \ - faligndata %F2, %F4, %A2 /* FPA Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fpadd32 %F2, %f2, %F2 /* FPA Group */; \ - add %src, 64, %src /* IEU0 */; \ - add %dst, 64, %dst /* IEU1 */; \ - fcmpgt32 %f0, %F0, %x1 /* FPM Group */; \ - inc %x7 /* IEU0 */; \ - STORE3 /* Store (optional) */; \ - faligndata %F4, %F6, %A4 /* FPA */; \ - srl %x7, 1, %x7 /* IEU0 Group */; \ - add %sum, %x6, %sum /* IEU1 */; \ - fpadd32 %F4, %f4, %F4 /* FPA */; \ - fcmpgt32 %f2, %F2, %x2 /* FPM Group */; \ - inc %x8 /* IEU0 */; \ - STORE4 /* Store (optional) */; \ - faligndata %F6, %F8, %A6 /* FPA */; \ - srl %x8, 1, %x8 /* IEU0 Group */; \ - add %sum, %x7, %sum /* IEU1 */; \ - fpadd32 %F6, %f6, %F6 /* FPA */; \ - fcmpgt32 %f4, %F4, %x3 /* FPM Group */; \ - inc %x1 /* IEU0 */; \ - STORE5 /* Store (optional) */; \ - faligndata %F8, %F10, %A8 /* FPA */; \ - srl %x1, 1, %x1 /* IEU0 Group */; \ - add %sum, %x8, %sum /* IEU1 */; \ - fpadd32 %F8, %f8, %F8 /* FPA */; \ - fcmpgt32 %f6, %F6, %x4 /* FPM Group */; \ - inc %x2 /* IEU0 */; \ - STORE6 /* Store (optional) */; \ - faligndata %F10, %F12, %A10 /* FPA */; \ - srl %x2, 1, %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - fpadd32 %F10, %f10, %F10 /* FPA */; \ - fcmpgt32 %f8, %F8, %x5 /* FPM Group */; \ - inc %x3 /* IEU0 */; \ - STORE7 /* Store (optional) */; \ - faligndata %F12, %F14, %A12 /* FPA */; \ - srl %x3, 1, %x3 /* IEU0 Group */; \ - add %sum, %x2, %sum /* IEU1 */; \ - fpadd32 %F12, %f12, %F12 /* FPA */; \ - fcmpgt32 %f10, %F10, %x6 /* FPM Group */; \ - inc %x4 /* IEU0 */; \ - STORE8 /* Store (optional) */; \ - fmovd %F14, %B14 /* FPA */; \ - srl %x4, 1, %x4 /* IEU0 Group */; \ - add %sum, %x3, %sum /* IEU1 */; \ - fpadd32 %F14, %f14, %F14 /* FPA */; \ - fcmpgt32 %f12, %F12, %x7 /* FPM Group */; \ - subcc %len, 64, %len /* IEU1 */; \ - BRANCH /* CTI */; \ - fcmpgt32 %f14, %F14, %x8 /* FPM Group */; \ + LOAD /* Load (Group) */; \ + faligndata %A14, %F0, %A14 /* FPA Group */; \ + inc %x5 /* IEU0 */; \ + STORE1 /* Store (optional) */; \ + faligndata %F0, %F2, %A0 /* FPA Group */; \ + srl %x5, 1, %x5 /* IEU0 */; \ + add %sum, %x4, %sum /* IEU1 */; \ + fpadd32 %F0, %f0, %F0 /* FPA Group */; \ + inc %x6 /* IEU0 */; \ + STORE2 /* Store (optional) */; \ + faligndata %F2, %F4, %A2 /* FPA Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fpadd32 %F2, %f2, %F2 /* FPA Group */; \ + add %src, 64, %src /* IEU0 */; \ + fcmpgt32 %f0, %F0, %x1 /* FPM */; \ + add %dst, 64, %dst /* IEU1 Group */; \ + inc %x7 /* IEU0 */; \ + STORE3 /* Store (optional) */; \ + faligndata %F4, %F6, %A4 /* FPA */; \ + fpadd32 %F4, %f4, %F4 /* FPA Group */; \ + add %sum, %x6, %sum /* IEU1 */; \ + fcmpgt32 %f2, %F2, %x2 /* FPM */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + inc %x8 /* IEU1 */; \ + STORE4 /* Store (optional) */; \ + faligndata %F6, %F8, %A6 /* FPA */; \ + fpadd32 %F6, %f6, %F6 /* FPA Group */; \ + srl %x8, 1, %x8 /* IEU0 */; \ + fcmpgt32 %f4, %F4, %x3 /* FPM */; \ + add %sum, %x7, %sum /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + STORE5 /* Store (optional) */; \ + faligndata %F8, %F10, %A8 /* FPA */; \ + fpadd32 %F8, %f8, %F8 /* FPA Group */; \ + srl %x1, 1, %x1 /* IEU0 */; \ + fcmpgt32 %f6, %F6, %x4 /* FPM */; \ + add %sum, %x8, %sum /* IEU0 Group */; \ + inc %x2 /* IEU1 */; \ + STORE6 /* Store (optional) */; \ + faligndata %F10, %F12, %A10 /* FPA */; \ + fpadd32 %F10, %f10, %F10 /* FPA Group */; \ + srl %x2, 1, %x2 /* IEU0 */; \ + fcmpgt32 %f8, %F8, %x5 /* FPM */; \ + add %sum, %x1, %sum /* IEU0 Group */; \ + inc %x3 /* IEU1 */; \ + STORE7 /* Store (optional) */; \ + faligndata %F12, %F14, %A12 /* FPA */; \ + fpadd32 %F12, %f12, %F12 /* FPA Group */; \ + srl %x3, 1, %x3 /* IEU0 */; \ + fcmpgt32 %f10, %F10, %x6 /* FPM */; \ + add %sum, %x2, %sum /* IEU0 Group */; \ + inc %x4 /* IEU1 */; \ + STORE8 /* Store (optional) */; \ + fmovd %F14, %B14 /* FPA */; \ + fpadd32 %F14, %f14, %F14 /* FPA Group */; \ + srl %x4, 1, %x4 /* IEU0 */; \ + fcmpgt32 %f12, %F12, %x7 /* FPM */; \ + add %sum, %x3, %sum /* IEU0 Group */; \ + subcc %len, 64, %len /* IEU1 */; \ + BRANCH /* CTI */; \ + fcmpgt32 %f14, %F14, %x8 /* FPM Group */; #define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \ - inc %x5 /* IEU0 Group */; \ - fpadd32 %f2, %f0, %S0 /* FPA */; \ - srl %x5, 1, %x5 /* IEU0 Group */; \ - add %sum, %x4, %sum /* IEU1 */; \ - fpadd32 %f6, %f4, %S1 /* FPA */; \ - inc %x6 /* IEU0 Group */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fcmpgt32 %f0, %S0, %x1 /* FPM Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - inc %x7 /* IEU1 */; \ - fpadd32 %f10, %f8, %S2 /* FPA */; \ - fcmpgt32 %f4, %S1, %x2 /* FPM Group */; \ - srl %x7, 1, %x7 /* IEU0 */; \ - add %sum, %x6, %sum /* IEU1 */; \ - fpadd32 %f14, %f12, %S3 /* FPA */; \ - inc %x8 /* IEU0 Group */; \ - add %sum, %x7, %sum /* IEU1 */; \ - fzero %fz /* FPA */; \ - fcmpgt32 %f8, %S2, %x3 /* FPM Group */; \ - srl %x8, 1, %x8 /* IEU0 */; \ - inc %x1 /* IEU1 */; \ - fpadd32 %S0, %S1, %T0 /* FPA */; \ - fcmpgt32 %f12, %S3, %x4 /* FPM Group */; \ - srl %x1, 1, %x1 /* IEU0 */; \ - add %sum, %x8, %sum /* IEU1 */; \ - fpadd32 %S2, %S3, %T1 /* FPA */; \ - inc %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - fcmpgt32 %S0, %T0, %x5 /* FPM Group */; \ - srl %x2, 1, %x2 /* IEU0 */; \ - inc %x3 /* IEU1 */; \ - fcmpgt32 %S2, %T1, %x6 /* FPM Group */; \ - srl %x3, 1, %x3 /* IEU0 */; \ - add %sum, %x2, %sum /* IEU1 */; \ - inc %x4 /* IEU0 Group */; \ - add %sum, %x3, %sum /* IEU1 */; \ - fcmpgt32 %fz, %f2, %x7 /* FPM Group */; \ - srl %x4, 1, %x4 /* IEU0 */; \ - inc %x5 /* IEU1 */; \ - fpadd32 %T0, %T1, %U0 /* FPA */; \ - fcmpgt32 %fz, %f6, %x8 /* FPM Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - add %sum, %x4, %sum /* IEU1 */; \ - inc %x6 /* IEU0 Group */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fcmpgt32 %fz, %f10, %x1 /* FPM Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - inc %x7 /* IEU1 */; \ - fcmpgt32 %fz, %f14, %x2 /* FPM Group */; \ - ba,pt %xcc, ett /* CTI */; \ - fmovd %FA, %FB /* FPA */; \ + inc %x5 /* IEU0 Group */; \ + fpadd32 %f2, %f0, %S0 /* FPA */; \ + add %sum, %x4, %sum /* IEU1 */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + fpadd32 %f6, %f4, %S1 /* FPA */; \ + inc %x6 /* IEU1 */; \ + fpadd32 %f10, %f8, %S2 /* FPA Group */; \ + add %sum, %x5, %sum /* IEU0 */; \ + fcmpgt32 %f0, %S0, %x1 /* FPM */; \ + fpadd32 %f14, %f12, %S3 /* FPA Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + fcmpgt32 %f4, %S1, %x2 /* FPM */; \ + add %sum, %x6, %sum /* IEU0 Group */; \ + fzero %fz /* FPA */; \ + fcmpgt32 %f8, %S2, %x3 /* FPM */; \ + inc %x7 /* IEU0 Group */; \ + inc %x8 /* IEU1 */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + fpadd32 %S0, %S1, %T0 /* FPA */; \ + fpadd32 %S2, %S3, %T1 /* FPA Group */; \ + add %sum, %x7, %sum /* IEU0 */; \ + fcmpgt32 %f12, %S3, %x4 /* FPM */; \ + srl %x8, 1, %x8 /* IEU0 Group */; \ + inc %x2 /* IEU1 */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + add %sum, %x8, %sum /* IEU1 */; \ + add %sum, %x1, %sum /* IEU0 Group */; \ + fcmpgt32 %S0, %T0, %x5 /* FPM */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + fcmpgt32 %S2, %T1, %x6 /* FPM */; \ + inc %x3 /* IEU0 Group */; \ + add %sum, %x2, %sum /* IEU1 */; \ + srl %x3, 1, %x3 /* IEU0 Group */; \ + inc %x4 /* IEU1 */; \ + fpadd32 %T0, %T1, %U0 /* FPA Group */; \ + add %sum, %x3, %sum /* IEU0 */; \ + fcmpgt32 %fz, %f2, %x7 /* FPM */; \ + srl %x4, 1, %x4 /* IEU0 Group */; \ + fcmpgt32 %fz, %f6, %x8 /* FPM */; \ + inc %x5 /* IEU0 Group */; \ + add %sum, %x4, %sum /* IEU1 */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + fcmpgt32 %fz, %f10, %x1 /* FPM */; \ + inc %x6 /* IEU0 Group */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fmovd %FA, %FB /* FPA Group */; \ + fcmpgt32 %fz, %f14, %x2 /* FPM */; \ + srl %x6, 1, %x6 /* IEU0 Group */; \ + ba,pt %xcc, ett /* CTI */; \ + inc %x7 /* IEU1 */; -#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \ +#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \ END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62) -#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \ - fpadd32 %U0, %U1, %V0 /* FPA Group */; \ - srl %x7, 1, %x7 /* IEU0 */; \ - add %sum, %x6, %sum /* IEU1 */; \ - std %V0, [%sp + STACKOFF] /* Store Group */; \ - inc %x8 /* IEU0 */; \ - sub %sum, %x7, %sum /* IEU1 */; \ - fcmpgt32 %fz, %S1, %x3 /* FPM Group */; \ - srl %x8, 1, %x8 /* IEU0 */; \ - inc %x1 /* IEU1 */; \ - fcmpgt32 %fz, %S3, %x4 /* FPM Group */; \ - srl %x1, 1, %x1 /* IEU0 */; \ - sub %sum, %x8, %sum /* IEU1 */; \ - ldx [%sp + STACKOFF], %x8 /* Load Group */; \ - inc %x2 /* IEU0 */; \ - sub %sum, %x1, %sum /* IEU1 */; \ - fcmpgt32 %fz, %T1, %x5 /* FPM Group */; \ - srl %x2, 1, %x2 /* IEU0 */; \ - inc %x3 /* IEU1 */; \ - fcmpgt32 %T0, %U0, %x6 /* FPM Group */; \ - srl %x3, 1, %x3 /* IEU0 */; \ - sub %sum, %x2, %sum /* IEU1 */; \ - inc %x4 /* IEU0 Group */; \ - sub %sum, %x3, %sum /* IEU1 */; \ - fcmpgt32 %fz, %U1, %x7 /* FPM Group */; \ - srl %x4, 1, %x4 /* IEU0 */; \ - inc %x5 /* IEU1 */; \ - fcmpgt32 %U0, %V0, %x1 /* FPM Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - sub %sum, %x4, %sum /* IEU1 */; \ - fcmpgt32 %fz, %V0, %x2 /* FPM Group */; \ - inc %x6 /* IEU0 */; \ - sub %sum, %x5, %sum /* IEU1 */; \ - srl %x6, 1, %x6 /* IEU0 Group */; \ - inc %x7 /* IEU1 */; \ - srl %x7, 1, %x7 /* IEU0 Group */; \ - add %sum, %x6, %sum /* IEU1 */; \ - inc %x1 /* IEU0 Group */; \ - sub %sum, %x7, %sum /* IEU1 */; \ - srl %x1, 1, %x1 /* IEU0 Group */; \ - inc %x2 /* IEU1 */; \ - srl %x2, 1, %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - sub %sum, %x2, %sum /* IEU0 Group */; \ - addcc %sum, %x8, %sum /* IEU Group */; \ - bcs,a,pn %xcc, 33f /* CTI */; \ - add %sum, 1, %sum /* IEU0 */; \ -33: /* That's it */; +#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \ + fpadd32 %U0, %U1, %V0 /* FPA Group */; \ + srl %x7, 1, %x7 /* IEU0 */; \ + add %sum, %x6, %sum /* IEU1 */; \ + std %V0, [%sp + STACKOFF] /* Store Group */; \ + inc %x8 /* IEU0 */; \ + sub %sum, %x7, %sum /* IEU1 */; \ + srl %x8, 1, %x8 /* IEU0 Group */; \ + fcmpgt32 %fz, %S1, %x3 /* FPM */; \ + inc %x1 /* IEU0 Group */; \ + fcmpgt32 %fz, %S3, %x4 /* FPM */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + sub %sum, %x8, %sum /* IEU1 */; \ + ldx [%sp + STACKOFF], %x8 /* Load Group */; \ + inc %x2 /* IEU0 */; \ + sub %sum, %x1, %sum /* IEU1 */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + fcmpgt32 %fz, %T1, %x5 /* FPM */; \ + inc %x3 /* IEU0 Group */; \ + fcmpgt32 %T0, %U0, %x6 /* FPM */; \ + srl %x3, 1, %x3 /* IEU0 Group */; \ + sub %sum, %x2, %sum /* IEU1 */; \ + inc %x4 /* IEU0 Group */; \ + sub %sum, %x3, %sum /* IEU1 */; \ + srl %x4, 1, %x4 /* IEU0 Group */; \ + fcmpgt32 %fz, %U1, %x7 /* FPM */; \ + inc %x5 /* IEU0 Group */; \ + fcmpgt32 %U0, %V0, %x1 /* FPM */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + sub %sum, %x4, %sum /* IEU1 */; \ + sub %sum, %x5, %sum /* IEU0 Group */; \ + fcmpgt32 %fz, %V0, %x2 /* FPM */; \ + inc %x6 /* IEU0 Group */; \ + inc %x7 /* IEU1 */; \ + srl %x6, 1, %x6 /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + add %sum, %x6, %sum /* IEU1 */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + sub %sum, %x7, %sum /* IEU1 */; \ + inc %x2 /* IEU0 Group */; \ + add %sum, %x1, %sum /* IEU1 */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + sub %sum, %x2, %sum /* IEU0 Group */; \ + addcc %sum, %x8, %sum /* IEU1 Group */; \ + bcs,a,pn %xcc, 33f /* CTI */; \ + add %sum, 1, %sum /* IEU0 (Group) */; \ +33: /* That's it */; .text .globl csum_partial_copy_vis .align 32 -/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp. csum_partial_copy_from_user */ -/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */ +/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp. + * csum_partial_copy_from_user + * This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 + */ csum_partial_copy_vis: - andcc %dst, 7, %g0 /* IEU1 Group */ - be,pt %icc, 4f /* CTI */ - and %dst, 0x38, %o4 /* IEU0 */ - mov 1, %g5 /* IEU0 Group */ - andcc %dst, 2, %g0 /* IEU1 */ - be,pt %icc, 1f /* CTI */ - and %dst, 4, %g7 /* IEU0 Group */ - lduha [%src] %asi, %g2 /* Load */ - sub %len, 2, %len /* IEU0 Group */ - add %dst, 2, %dst /* IEU1 */ - andcc %dst, 4, %g7 /* IEU1 Group */ - sll %g5, 16, %g5 /* IEU0 */ - sth %g2, [%dst - 2] /* Store Group */ - sll %g2, 16, %g2 /* IEU0 */ - add %src, 2, %src /* IEU1 */ - addcc %g2, %sum, %sum /* IEU1 Group */ - bcs,a,pn %icc, 1f /* CTI */ - add %sum, %g5, %sum /* IEU0 */ -1: lduwa [%src] %asi, %g2 /* Load */ - brz,a,pn %g7, 4f /* CTI+IEU1 Group */ - and %dst, 0x38, %o4 /* IEU0 */ - add %dst, 4, %dst /* IEU0 Group */ - sub %len, 4, %len /* IEU1 */ - addcc %g2, %sum, %sum /* IEU1 Group */ - bcs,a,pn %icc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: and %dst, 0x38, %o4 /* IEU0 Group */ - stw %g2, [%dst - 4] /* Store */ - add %src, 4, %src /* IEU1 */ + andcc %dst, 7, %g0 /* IEU1 Group */ + be,pt %icc, 4f /* CTI */ + and %dst, 0x38, %o4 /* IEU0 */ + mov 1, %g5 /* IEU0 Group */ + andcc %dst, 2, %g0 /* IEU1 */ + be,pt %icc, 1f /* CTI */ + and %dst, 4, %g7 /* IEU0 Group */ + lduha [%src] %asi, %g2 /* Load */ + sub %len, 2, %len /* IEU0 Group */ + add %dst, 2, %dst /* IEU1 */ + andcc %dst, 4, %g7 /* IEU1 Group */ + sll %g5, 16, %g5 /* IEU0 */ + sth %g2, [%dst - 2] /* Store Group */ + sll %g2, 16, %g2 /* IEU0 */ + add %src, 2, %src /* IEU1 */ + addcc %g2, %sum, %sum /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %sum, %g5, %sum /* IEU0 */ +1: lduwa [%src] %asi, %g2 /* Load */ + brz,a,pn %g7, 4f /* CTI+IEU1 Group */ + and %dst, 0x38, %o4 /* IEU0 */ + add %dst, 4, %dst /* IEU0 Group */ + sub %len, 4, %len /* IEU1 */ + addcc %g2, %sum, %sum /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: and %dst, 0x38, %o4 /* IEU0 Group */ + stw %g2, [%dst - 4] /* Store */ + add %src, 4, %src /* IEU1 */ 4: #ifdef __KERNEL__ VISEntry #endif - mov %src, %g7 /* IEU1 Group */ - fzero %f48 /* FPA */ - alignaddr %src, %g0, %src /* Single Group */ - subcc %g7, %src, %g7 /* IEU1 Group */ - be,pt %xcc, 1f /* CTI */ - mov 0x40, %g1 /* IEU0 */ - lduwa [%src] %asi, %g2 /* Load Group */ - subcc %sum, %g2, %sum /* IEU1 Group+load stall */ - bcs,a,pn %icc, 1f /* CTI */ - sub %sum, 1, %sum /* IEU0 */ -1: srl %sum, 0, %sum /* IEU0 Group */ - clr %g5 /* IEU1 */ - brz,pn %o4, 3f /* CTI+IEU1 Group */ - sub %g1, %o4, %g1 /* IEU0 */ - ldda [%src] %asi, %f0 /* Load */ - clr %o4 /* IEU0 Group */ - andcc %dst, 8, %g0 /* IEU1 */ - be,pn %icc, 1f /* CTI */ - ldda [%src + 8] %asi, %f2 /* Load Group */ - add %src, 8, %src /* IEU0 */ - sub %len, 8, %len /* IEU1 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - addcc %dst, 8, %dst /* IEU1 Group */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %o4 /* FPM Group */ - fmovd %f2, %f0 /* FPA Group */ - ldda [%src + 8] %asi, %f2 /* Load */ - std %f16, [%dst - 8] /* Store */ - fmovd %f50, %f48 /* FPA */ -1: andcc %g1, 0x10, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - and %g1, 0x20, %g1 /* IEU0 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - ldda [%src + 16] %asi, %f4 /* Load Group */ - add %src, 16, %src /* IEU0 */ - add %dst, 16, %dst /* IEU1 */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %g5 /* FPM Group */ - sub %len, 16, %len /* IEU0 */ - inc %o4 /* IEU1 */ - std %f16, [%dst - 16] /* Store Group */ - fpadd32 %f2, %f50, %f48 /* FPA */ - srl %o4, 1, %o5 /* IEU0 */ - faligndata %f2, %f4, %f18 /* FPA Group */ - std %f18, [%dst - 8] /* Store */ - fcmpgt32 %f50, %f48, %o4 /* FPM Group */ - add %o5, %sum, %sum /* IEU0 */ - ldda [%src + 8] %asi, %f2 /* Load */ - fmovd %f4, %f0 /* FPA */ -1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */ - rd %asi, %g2 /* LSU Group + 4 bubbles */ - inc %g5 /* IEU0 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - ldda [%src + 16] %asi, %f4 /* Load Group */ - srl %g5, 1, %g5 /* IEU0 */ - add %dst, 32, %dst /* IEU1 */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %o5 /* FPM Group */ - inc %o4 /* IEU0 */ - ldda [%src + 24] %asi, %f6 /* Load */ - srl %o4, 1, %o4 /* IEU0 Group */ - add %g5, %sum, %sum /* IEU1 */ - ldda [%src + 32] %asi, %f8 /* Load */ - fpadd32 %f2, %f50, %f48 /* FPA */ - faligndata %f2, %f4, %f18 /* FPA Group */ - sub %len, 32, %len /* IEU0 */ - std %f16, [%dst - 32] /* Store */ - fcmpgt32 %f50, %f48, %g3 /* FPM Group */ - inc %o5 /* IEU0 */ - add %o4, %sum, %sum /* IEU1 */ - fpadd32 %f4, %f48, %f50 /* FPA */ - faligndata %f4, %f6, %f20 /* FPA Group */ - srl %o5, 1, %o5 /* IEU0 */ - fcmpgt32 %f48, %f50, %g5 /* FPM Group */ - add %o5, %sum, %sum /* IEU0 */ - std %f18, [%dst - 24] /* Store */ - fpadd32 %f6, %f50, %f48 /* FPA */ - inc %g3 /* IEU0 Group */ - std %f20, [%dst - 16] /* Store */ - add %src, 32, %src /* IEU1 */ - faligndata %f6, %f8, %f22 /* FPA */ - fcmpgt32 %f50, %f48, %o4 /* FPM Group */ - srl %g3, 1, %g3 /* IEU0 */ - std %f22, [%dst - 8] /* Store */ - add %g3, %sum, %sum /* IEU0 Group */ -3: rd %asi, %g2 /* LSU Group + 4 bubbles */ + mov %src, %g7 /* IEU1 Group */ + fzero %f48 /* FPA */ + alignaddr %src, %g0, %src /* Single Group */ + subcc %g7, %src, %g7 /* IEU1 Group */ + be,pt %xcc, 1f /* CTI */ + mov 0x40, %g1 /* IEU0 */ + lduwa [%src] %asi, %g2 /* Load Group */ + subcc %sum, %g2, %sum /* IEU1 Group+load stall*/ + bcs,a,pn %icc, 1f /* CTI */ + sub %sum, 1, %sum /* IEU0 */ +1: srl %sum, 0, %sum /* IEU0 Group */ + clr %g5 /* IEU1 */ + brz,pn %o4, 3f /* CTI+IEU1 Group */ + sub %g1, %o4, %g1 /* IEU0 */ + ldda [%src] %asi, %f0 /* Load */ + clr %o4 /* IEU0 Group */ + andcc %dst, 8, %g0 /* IEU1 */ + be,pn %icc, 1f /* CTI */ + ldda [%src + 8] %asi, %f2 /* Load Group */ + add %src, 8, %src /* IEU0 */ + sub %len, 8, %len /* IEU1 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + addcc %dst, 8, %dst /* IEU1 Group */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %o4 /* FPM Group */ + fmovd %f2, %f0 /* FPA Group */ + ldda [%src + 8] %asi, %f2 /* Load */ + std %f16, [%dst - 8] /* Store */ + fmovd %f50, %f48 /* FPA */ +1: andcc %g1, 0x10, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + and %g1, 0x20, %g1 /* IEU0 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + ldda [%src + 16] %asi, %f4 /* Load Group */ + add %src, 16, %src /* IEU0 */ + add %dst, 16, %dst /* IEU1 */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %g5 /* FPM Group */ + sub %len, 16, %len /* IEU0 */ + inc %o4 /* IEU1 */ + std %f16, [%dst - 16] /* Store Group */ + fpadd32 %f2, %f50, %f48 /* FPA */ + srl %o4, 1, %o5 /* IEU0 */ + faligndata %f2, %f4, %f18 /* FPA Group */ + std %f18, [%dst - 8] /* Store */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + add %o5, %sum, %sum /* IEU0 */ + ldda [%src + 8] %asi, %f2 /* Load */ + fmovd %f4, %f0 /* FPA */ +1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */ + rd %asi, %g2 /* LSU Group + 4 bubbles*/ + inc %g5 /* IEU0 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + ldda [%src + 16] %asi, %f4 /* Load Group */ + srl %g5, 1, %g5 /* IEU0 */ + add %dst, 32, %dst /* IEU1 */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %o5 /* FPM Group */ + inc %o4 /* IEU0 */ + ldda [%src + 24] %asi, %f6 /* Load */ + srl %o4, 1, %o4 /* IEU0 Group */ + add %g5, %sum, %sum /* IEU1 */ + ldda [%src + 32] %asi, %f8 /* Load */ + fpadd32 %f2, %f50, %f48 /* FPA */ + faligndata %f2, %f4, %f18 /* FPA Group */ + sub %len, 32, %len /* IEU0 */ + std %f16, [%dst - 32] /* Store */ + fcmpgt32 %f50, %f48, %g3 /* FPM Group */ + inc %o5 /* IEU0 */ + add %o4, %sum, %sum /* IEU1 */ + fpadd32 %f4, %f48, %f50 /* FPA */ + faligndata %f4, %f6, %f20 /* FPA Group */ + srl %o5, 1, %o5 /* IEU0 */ + fcmpgt32 %f48, %f50, %g5 /* FPM Group */ + add %o5, %sum, %sum /* IEU0 */ + std %f18, [%dst - 24] /* Store */ + fpadd32 %f6, %f50, %f48 /* FPA */ + inc %g3 /* IEU0 Group */ + std %f20, [%dst - 16] /* Store */ + add %src, 32, %src /* IEU1 */ + faligndata %f6, %f8, %f22 /* FPA */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + srl %g3, 1, %g3 /* IEU0 */ + std %f22, [%dst - 8] /* Store */ + add %g3, %sum, %sum /* IEU0 Group */ +3: rd %asi, %g2 /* LSU Group + 4 bubbles*/ #ifdef __KERNEL__ -4: sethi %hi(vis0s), %g7 /* IEU0 Group */ - or %g2, ASI_BLK_OR, %g2 /* IEU1 */ +4: sethi %hi(vis0s), %g7 /* IEU0 Group */ + or %g2, ASI_BLK_OR, %g2 /* IEU1 */ #else -4: rd %pc, %g7 /* LSU Group + 4 bubbles */ +4: rd %pc, %g7 /* LSU Group + 4 bubbles*/ #endif - inc %g5 /* IEU0 Group */ - and %src, 0x38, %g3 /* IEU1 */ - membar #StoreLoad /* LSU Group */ - srl %g5, 1, %g5 /* IEU0 */ - inc %o4 /* IEU1 */ - sll %g3, 8, %g3 /* IEU0 Group */ - sub %len, 0xc0, %len /* IEU1 */ - addcc %g5, %sum, %sum /* IEU1 Group */ - srl %o4, 1, %o4 /* IEU0 */ - add %g7, %g3, %g7 /* IEU0 Group */ - add %o4, %sum, %sum /* IEU1 */ + inc %g5 /* IEU0 Group */ + and %src, 0x38, %g3 /* IEU1 */ + membar #StoreLoad /* LSU Group */ + srl %g5, 1, %g5 /* IEU0 */ + inc %o4 /* IEU1 */ + sll %g3, 8, %g3 /* IEU0 Group */ + sub %len, 0xc0, %len /* IEU1 */ + addcc %g5, %sum, %sum /* IEU1 Group */ + srl %o4, 1, %o4 /* IEU0 */ + add %g7, %g3, %g7 /* IEU0 Group */ + add %o4, %sum, %sum /* IEU1 */ #ifdef __KERNEL__ - jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */ + jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */ #else - jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */ + jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */ #endif - fzero %f32 /* FPA */ + fzero %f32 /* FPA */ .align 2048 -vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - add %src, 128, %src /* IEU0 Group */ - ldda [%src-128] %asi, %f0 /* Load Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f48, %f62 /* FPA Group f0 available */ - faligndata %f0, %f2, %f48 /* FPA Group f2 available */ - fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available */ - fpadd32 %f0, %f62, %f0 /* FPA */ - fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available */ - faligndata %f2, %f4, %f50 /* FPA */ - fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available */ - faligndata %f4, %f6, %f52 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available */ - inc %x1 /* IEU0 */ - faligndata %f6, %f8, %f54 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available */ - srl %x1, 1, %x1 /* IEU0 */ - inc %x2 /* IEU1 */ - faligndata %f8, %f10, %f56 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available */ - srl %x2, 1, %x2 /* IEU0 */ - add %sum, %x1, %sum /* IEU1 */ - faligndata %f10, %f12, %f58 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - add %sum, %x2, %sum /* IEU1 */ - faligndata %f12, %f14, %f60 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f62 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f62 /* FPA Group f0 available*/ + faligndata %f0, %f2, %f48 /* FPA Group f2 available*/ + fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available*/ + fpadd32 %f0, %f62, %f0 /* FPA */ + fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available*/ + faligndata %f2, %f4, %f50 /* FPA */ + fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available*/ + faligndata %f4, %f6, %f52 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available*/ + inc %x1 /* IEU0 */ + faligndata %f6, %f8, %f54 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available*/ + srl %x1, 1, %x1 /* IEU0 */ + inc %x2 /* IEU1 */ + faligndata %f8, %f10, %f56 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available*/ + srl %x2, 1, %x2 /* IEU0 */ + add %sum, %x1, %sum /* IEU1 */ + faligndata %f10, %f12, %f58 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + add %sum, %x2, %sum /* IEU1 */ + faligndata %f12, %f14, %f60 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f62 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis0: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, - ,f48,f50,f52,f54,f56,f58,f60,f62,f62, - ,LDBLK(f32), STBLK,,,,,,,, + ,f48,f50,f52,f54,f56,f58,f60,f62,f62, + ,LDBLK(f32), STBLK,,,,,,,, ,bcs,pn %icc, vis0e1) DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, - ,f48,f50,f52,f54,f56,f58,f60,f62,f62, - ,LDBLK(f0), STBLK,,,,,,,, + ,f48,f50,f52,f54,f56,f58,f60,f62,f62, + ,LDBLK(f0), STBLK,,,,,,,, ,bcs,pn %icc, vis0e2) - DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, ,f48,f50,f52,f54,f56,f58,f60,f62,f62, ,LDBLK(f16), STBLK,,,,,,,, ,bcc,pt %icc, vis0) -vis0e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, +vis0e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f48,f50,f52,f54,f56,f58,f60,f62,f32, ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2) @@ -447,39 +449,39 @@ ,f48,f50,f52,f54,f56,f58,f60,f62,f0, ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3) -vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, +vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, ,f48,f50,f52,f54,f56,f58,f60,f62,f16, ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1) .align 2048 -vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - add %src, 128 - 8, %src /* IEU0 Group */ - ldda [%src-128] %asi, %f0 /* Load Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f0, %f58 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - fcmpgt32 %f32, %f2, %x2 /* FPM Group */ - faligndata %f2, %f4, %f48 /* FPA */ - fcmpgt32 %f32, %f4, %x3 /* FPM Group */ - faligndata %f4, %f6, %f50 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f52 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - inc %x2 /* IEU1 */ - faligndata %f8, %f10, %f54 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - srl %x2, 1, %x2 /* IEU0 */ - faligndata %f10, %f12, %f56 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - add %sum, %x2, %sum /* IEU1 */ - faligndata %f12, %f14, %f58 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f60 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 8, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f0, %f58 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + fcmpgt32 %f32, %f2, %x2 /* FPM Group */ + faligndata %f2, %f4, %f48 /* FPA */ + fcmpgt32 %f32, %f4, %x3 /* FPM Group */ + faligndata %f4, %f6, %f50 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f52 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + inc %x2 /* IEU1 */ + faligndata %f8, %f10, %f54 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + srl %x2, 1, %x2 /* IEU0 */ + faligndata %f10, %f12, %f56 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + add %sum, %x2, %sum /* IEU1 */ + faligndata %f12, %f14, %f58 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f60 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis1: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f62,f48,f50,f52,f54,f56,f58,f60,f60, ,LDBLK(f32), ,STBLK,,,,,,, @@ -505,31 +507,31 @@ ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40), ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1) .align 2048 -vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - add %src, 128 - 16, %src /* IEU0 Group */ - ldda [%src-128] %asi, %f0 /* Load Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f0, %f56 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fcmpgt32 %f32, %f4, %x3 /* FPM Group */ - faligndata %f4, %f6, %f48 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f50 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f52 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f54 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - faligndata %f12, %f14, %f56 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f58 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 16, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f0, %f56 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fcmpgt32 %f32, %f4, %x3 /* FPM Group */ + faligndata %f4, %f6, %f48 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f50 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f52 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f54 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + faligndata %f12, %f14, %f56 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f58 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis2: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f60,f62,f48,f50,f52,f54,f56,f58,f58, ,LDBLK(f32), ,,STBLK,,,,,, @@ -555,27 +557,27 @@ ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96), ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1) .align 2048 -vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - add %src, 128 - 24, %src /* IEU0 Group */ - ldda [%src-128] %asi, %f0 /* Load Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f0, %f54 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fpsub32 %f4, %f4, %f4 /* FPA Group */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f48 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f50 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f52 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f54 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f56 /* FPA */ - inc %x4 /* IEU0 */ - srl %x4, 1, %x4 /* IEU0 Group */ +vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 24, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f0, %f54 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fpsub32 %f4, %f4, %f4 /* FPA Group */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f48 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f50 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f52 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f54 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f56 /* FPA */ + inc %x4 /* IEU0 */ + srl %x4, 1, %x4 /* IEU0 Group */ vis3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f58,f60,f62,f48,f50,f52,f54,f56,f56, ,LDBLK(f32), ,,,STBLK,,,,, @@ -601,25 +603,25 @@ ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88), ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1) .align 2048 -vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - add %src, 128 - 32, %src /* IEU0 Group */ - ldda [%src-128] %asi, %f0 /* Load Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f0, %f52 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fpsub32 %f4, %f4, %f4 /* FPA Group */ - fpsub32 %f6, %f6, %f6 /* FPA Group */ - clr %x4 /* IEU0 */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f48 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f50 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f52 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f54 /* FPA */ +vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 32, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f0, %f52 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fpsub32 %f4, %f4, %f4 /* FPA Group */ + fpsub32 %f6, %f6, %f6 /* FPA Group */ + clr %x4 /* IEU0 */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f48 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f50 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f52 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f54 /* FPA */ vis4: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f56,f58,f60,f62,f48,f50,f52,f54,f54, ,LDBLK(f32), ,,,,STBLK,,,, @@ -645,26 +647,26 @@ ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80), ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1) .align 2048 -vis5s: add %src, 128 - 40, %src /* IEU0 Group */ - ldda [%src-88] %asi, %f10 /* Load Group */ - ldda [%src-80] %asi, %f12 /* Load Group */ - ldda [%src-72] %asi, %f14 /* Load Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - faligndata %f10, %f12, %f48 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f50 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f52 /* FPA */ +vis5s: add %src, 128 - 40, %src /* IEU0 Group */ + ldda [%src-88] %asi, %f10 /* Load Group */ + ldda [%src-80] %asi, %f12 /* Load Group */ + ldda [%src-72] %asi, %f14 /* Load Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + faligndata %f10, %f12, %f48 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f50 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f52 /* FPA */ vis5: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f54,f56,f58,f60,f62,f48,f50,f52,f52, ,LDBLK(f32), ,,,,,STBLK,,, @@ -690,25 +692,25 @@ ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72), ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1) .align 2048 -vis6s: add %src, 128 - 48, %src /* IEU0 Group */ - ldda [%src-80] %asi, %f12 /* Load Group */ - ldda [%src-72] %asi, %f14 /* Load Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fmuld %f32, %f32, %f10 /* FPM */ - clr %x6 /* IEU0 */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - faligndata %f12, %f14, %f48 /* FPA */ - fmovd %f14, %f50 /* FPA Group */ +vis6s: add %src, 128 - 48, %src /* IEU0 Group */ + ldda [%src-80] %asi, %f12 /* Load Group */ + ldda [%src-72] %asi, %f14 /* Load Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fmuld %f32, %f32, %f10 /* FPM */ + clr %x6 /* IEU0 */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + faligndata %f12, %f14, %f48 /* FPA */ + fmovd %f14, %f50 /* FPA Group */ vis6: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f52,f54,f56,f58,f60,f62,f48,f50,f50, ,LDBLK(f32), ,,,,,,STBLK,, @@ -734,24 +736,24 @@ ,SYNC, ,,,,,,STBLK,ST(f48,64), ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1) .align 2048 -vis7s: add %src, 128 - 56, %src /* IEU0 Group */ - ldda [%src-72] %asi, %f14 /* Load Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src-64] %asi, %f16 /* Load Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fmuld %f32, %f32, %f10 /* FPM */ - clr %x6 /* IEU0 */ - faddd %f32, %f32, %f12 /* FPA Group */ - clr %x7 /* IEU0 */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - fmovd %f14, %f48 /* FPA */ +vis7s: add %src, 128 - 56, %src /* IEU0 Group */ + ldda [%src-72] %asi, %f14 /* Load Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fmuld %f32, %f32, %f10 /* FPM */ + clr %x6 /* IEU0 */ + faddd %f32, %f32, %f12 /* FPA Group */ + clr %x7 /* IEU0 */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + fmovd %f14, %f48 /* FPA */ vis7: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f50,f52,f54,f56,f58,f60,f62,f48,f48, ,LDBLK(f32), ,,,,,,,STBLK, @@ -779,112 +781,112 @@ e1: END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6) e2: END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6) e3: END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6) -ett: rd %asi, %x4 /* LSU Group+4bubbles */ - rd %gsr, %x3 /* LSU Group+4bubbles */ +ett: rd %asi, %x4 /* LSU Group+4bubbles */ + rd %gsr, %x3 /* LSU Group+4bubbles */ #ifdef __KERNEL__ - srl %x4, 3, %x5 /* IEU0 Group */ - xor %x4, ASI_BLK_XOR1, %x4 /* IEU1 */ - wr %x4, %x5, %asi /* LSU Group+4bubbles */ + srl %x4, 3, %x5 /* IEU0 Group */ + xor %x4, ASI_BLK_XOR1, %x4 /* IEU1 */ + wr %x4, %x5, %asi /* LSU Group+4bubbles */ #else - wr %x4, ASI_BLK_XOR, %asi /* LSU Group+4bubbles */ + wr %x4, ASI_BLK_XOR, %asi /* LSU Group+4bubbles */ #endif - andcc %x3, 7, %x3 /* IEU1 Group */ - add %dst, 8, %dst /* IEU0 */ - bne,pn %icc, 1f /* CTI */ - fzero %f10 /* FPA */ - brz,a,pn %len, 2f /* CTI+IEU1 Group */ - std %f6, [%dst - 8] /* Store */ -1: cmp %len, 8 /* IEU1 */ - blu,pn %icc, 3f /* CTI */ - sub %src, 64, %src /* IEU0 Group */ -1: ldda [%src] %asi, %f2 /* Load Group */ - fpadd32 %f10, %f2, %f12 /* FPA Group+load stall */ - add %src, 8, %src /* IEU0 */ - add %dst, 8, %dst /* IEU1 */ - faligndata %f6, %f2, %f14 /* FPA Group */ - fcmpgt32 %f10, %f12, %x5 /* FPM Group */ - std %f14, [%dst - 16] /* Store */ - fmovd %f2, %f6 /* FPA */ - fmovd %f12, %f10 /* FPA Group */ - sub %len, 8, %len /* IEU1 */ - fzero %f16 /* FPA Group - FPU nop */ - fzero %f18 /* FPA Group - FPU nop */ - inc %x5 /* IEU0 */ - srl %x5, 1, %x5 /* IEU0 Group (regdep) */ - cmp %len, 8 /* IEU1 */ - bgeu,pt %icc, 1b /* CTI */ - add %x5, %sum, %sum /* IEU0 Group */ -3: brz,a,pt %x3, 2f /* CTI+IEU1 */ - std %f6, [%dst - 8] /* Store Group */ - st %f7, [%dst - 8] /* Store Group */ - sub %dst, 4, %dst /* IEU0 */ - add %len, 4, %len /* IEU1 */ + andcc %x3, 7, %x3 /* IEU1 Group */ + add %dst, 8, %dst /* IEU0 */ + bne,pn %icc, 1f /* CTI */ + fzero %f10 /* FPA */ + brz,a,pn %len, 2f /* CTI+IEU1 Group */ + std %f6, [%dst - 8] /* Store */ +1: cmp %len, 8 /* IEU1 */ + blu,pn %icc, 3f /* CTI */ + sub %src, 64, %src /* IEU0 Group */ +1: ldda [%src] %asi, %f2 /* Load Group */ + fpadd32 %f10, %f2, %f12 /* FPA Group+load stall*/ + add %src, 8, %src /* IEU0 */ + add %dst, 8, %dst /* IEU1 */ + faligndata %f6, %f2, %f14 /* FPA Group */ + fcmpgt32 %f10, %f12, %x5 /* FPM Group */ + std %f14, [%dst - 16] /* Store */ + fmovd %f2, %f6 /* FPA */ + fmovd %f12, %f10 /* FPA Group */ + sub %len, 8, %len /* IEU1 */ + fzero %f16 /* FPA Group - FPU nop */ + fzero %f18 /* FPA Group - FPU nop */ + inc %x5 /* IEU0 */ + srl %x5, 1, %x5 /* IEU0 Group (regdep) */ + cmp %len, 8 /* IEU1 */ + bgeu,pt %icc, 1b /* CTI */ + add %x5, %sum, %sum /* IEU0 Group */ +3: brz,a,pt %x3, 2f /* CTI+IEU1 */ + std %f6, [%dst - 8] /* Store Group */ + st %f7, [%dst - 8] /* Store Group */ + sub %dst, 4, %dst /* IEU0 */ + add %len, 4, %len /* IEU1 */ 2: #ifdef __KERNEL__ - sub %sp, 8, %sp /* IEU0 Group */ + sub %sp, 8, %sp /* IEU0 Group */ #endif END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62) - membar #Sync /* LSU Group */ + membar #Sync /* LSU Group */ #ifdef __KERNEL__ VISExit - add %sp, 8, %sp /* IEU0 Group */ + add %sp, 8, %sp /* IEU0 Group */ #endif -23: brnz,pn %len, 26f /* CTI+IEU1 Group */ -24: sllx %sum, 32, %g1 /* IEU0 */ -25: addcc %sum, %g1, %src /* IEU1 Group */ - srlx %src, 32, %src /* IEU0 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %src, 1, %src /* IEU1 */ +23: brnz,pn %len, 26f /* CTI+IEU1 Group */ +24: sllx %sum, 32, %g1 /* IEU0 */ +25: addcc %sum, %g1, %src /* IEU1 Group */ + srlx %src, 32, %src /* IEU0 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %src, 1, %src /* IEU1 */ #ifndef __KERNEL__ -1: retl /* CTI Group brk forced */ - srl %src, 0, %src /* IEU0 */ +1: retl /* CTI Group brk forced*/ + srl %src, 0, %src /* IEU0 */ #else -1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */ - retl /* CTI Group brk forced */ - sllx %g4, 32, %g4 /* IEU0 */ +1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */ + retl /* CTI Group brk forced*/ + sllx %g4, 32, %g4 /* IEU0 */ #endif -26: andcc %len, 8, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - lduwa [%src] %asi, %o4 /* Load */ - lduwa [%src+4] %asi, %g2 /* Load Group */ - add %src, 8, %src /* IEU0 */ - add %dst, 8, %dst /* IEU1 */ - sllx %o4, 32, %g5 /* IEU0 Group */ - stw %o4, [%dst - 8] /* Store */ - or %g5, %g2, %g5 /* IEU0 Group */ - stw %g2, [%dst - 4] /* Store */ - addcc %g5, %sum, %sum /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: andcc %len, 4, %g0 /* IEU1 Group */ - be,a,pn %icc, 1f /* CTI */ - clr %g2 /* IEU0 */ - lduwa [%src] %asi, %g7 /* Load */ - add %src, 4, %src /* IEU0 Group */ - add %dst, 4, %dst /* IEU1 */ - sllx %g7, 32, %g2 /* IEU0 Group */ - stw %g7, [%dst - 4] /* Store */ -1: andcc %len, 2, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %g3 /* IEU0 Group */ - lduha [%src] %asi, %g7 /* Load */ - add %src, 2, %src /* IEU1 */ - add %dst, 2, %dst /* IEU0 Group */ - sll %g7, 16, %g3 /* IEU0 Group */ - sth %g7, [%dst - 2] /* Store */ -1: andcc %len, 1, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o5 /* IEU0 Group */ - lduba [%src] %asi, %g7 /* Load */ - sll %g7, 8, %o5 /* IEU0 Group */ - stb %g7, [%dst] /* Store */ -1: or %g2, %g3, %g3 /* IEU1 */ - or %o5, %g3, %g3 /* IEU0 Group (regdep) */ - addcc %g3, %sum, %sum /* IEU1 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: ba,pt %xcc, 25b /* CTI Group */ - sllx %sum, 32, %g1 /* IEU0 */ +26: andcc %len, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + lduwa [%src] %asi, %o4 /* Load */ + lduwa [%src+4] %asi, %g2 /* Load Group */ + add %src, 8, %src /* IEU0 */ + add %dst, 8, %dst /* IEU1 */ + sllx %o4, 32, %g5 /* IEU0 Group */ + stw %o4, [%dst - 8] /* Store */ + or %g5, %g2, %g5 /* IEU0 Group */ + stw %g2, [%dst - 4] /* Store */ + addcc %g5, %sum, %sum /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: andcc %len, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + lduwa [%src] %asi, %g7 /* Load */ + add %src, 4, %src /* IEU0 Group */ + add %dst, 4, %dst /* IEU1 */ + sllx %g7, 32, %g2 /* IEU0 Group */ + stw %g7, [%dst - 4] /* Store */ +1: andcc %len, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %g3 /* IEU0 Group */ + lduha [%src] %asi, %g7 /* Load */ + add %src, 2, %src /* IEU1 */ + add %dst, 2, %dst /* IEU0 Group */ + sll %g7, 16, %g3 /* IEU0 Group */ + sth %g7, [%dst - 2] /* Store */ +1: andcc %len, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + lduba [%src] %asi, %g7 /* Load */ + sll %g7, 8, %o5 /* IEU0 Group */ + stb %g7, [%dst] /* Store */ +1: or %g2, %g3, %g3 /* IEU1 */ + or %o5, %g3, %g3 /* IEU0 Group (regdep) */ + addcc %g3, %sum, %sum /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %sum, 32, %g1 /* IEU0 */ #ifdef __KERNEL__ end: diff -u --recursive --new-file v2.3.47/linux/arch/sparc64/lib/VIScsumcopyusr.S linux/arch/sparc64/lib/VIScsumcopyusr.S --- v2.3.47/linux/arch/sparc64/lib/VIScsumcopyusr.S Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc64/lib/VIScsumcopyusr.S Mon Feb 21 16:32:27 2000 @@ -1,4 +1,4 @@ -/* $Id: VIScsumcopyusr.S,v 1.1 2000/01/19 04:06:04 davem Exp $ +/* $Id: VIScsumcopyusr.S,v 1.2 2000/02/20 23:21:40 davem Exp $ * VIScsumcopyusr.S: High bandwidth IP checksumming with simultaneous * copying utilizing the UltraSparc Visual Instruction Set. * @@ -91,358 +91,360 @@ #define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DUMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \ - LOAD /* Load Group */; \ - faligndata %A14, %F0, %A14 /* FPA Group */; \ - inc %x5 /* IEU0 */; \ - STORE1 /* Store (optional) */; \ - faligndata %F0, %F2, %A0 /* FPA Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - add %sum, %x4, %sum /* IEU1 */; \ - fpadd32 %F0, %f0, %F0 /* FPA Group */; \ - inc %x6 /* IEU0 */; \ - STORE2 /* Store (optional) */; \ - faligndata %F2, %F4, %A2 /* FPA Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fpadd32 %F2, %f2, %F2 /* FPA Group */; \ - add %src, 64, %src /* IEU0 */; \ - add %dst, 64, %dst /* IEU1 */; \ - fcmpgt32 %f0, %F0, %x1 /* FPM Group */; \ - inc %x7 /* IEU0 */; \ - STORE3 /* Store (optional) */; \ - faligndata %F4, %F6, %A4 /* FPA */; \ - srl %x7, 1, %x7 /* IEU0 Group */; \ - add %sum, %x6, %sum /* IEU1 */; \ - fpadd32 %F4, %f4, %F4 /* FPA */; \ - fcmpgt32 %f2, %F2, %x2 /* FPM Group */; \ - inc %x8 /* IEU0 */; \ - STORE4 /* Store (optional) */; \ - faligndata %F6, %F8, %A6 /* FPA */; \ - srl %x8, 1, %x8 /* IEU0 Group */; \ - add %sum, %x7, %sum /* IEU1 */; \ - fpadd32 %F6, %f6, %F6 /* FPA */; \ - fcmpgt32 %f4, %F4, %x3 /* FPM Group */; \ - inc %x1 /* IEU0 */; \ - STORE5 /* Store (optional) */; \ - faligndata %F8, %F10, %A8 /* FPA */; \ - srl %x1, 1, %x1 /* IEU0 Group */; \ - add %sum, %x8, %sum /* IEU1 */; \ - fpadd32 %F8, %f8, %F8 /* FPA */; \ - fcmpgt32 %f6, %F6, %x4 /* FPM Group */; \ - inc %x2 /* IEU0 */; \ - STORE6 /* Store (optional) */; \ - faligndata %F10, %F12, %A10 /* FPA */; \ - srl %x2, 1, %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - fpadd32 %F10, %f10, %F10 /* FPA */; \ - fcmpgt32 %f8, %F8, %x5 /* FPM Group */; \ - inc %x3 /* IEU0 */; \ - STORE7 /* Store (optional) */; \ - faligndata %F12, %F14, %A12 /* FPA */; \ - srl %x3, 1, %x3 /* IEU0 Group */; \ - add %sum, %x2, %sum /* IEU1 */; \ - fpadd32 %F12, %f12, %F12 /* FPA */; \ - fcmpgt32 %f10, %F10, %x6 /* FPM Group */; \ - inc %x4 /* IEU0 */; \ - STORE8 /* Store (optional) */; \ - fmovd %F14, %B14 /* FPA */; \ - srl %x4, 1, %x4 /* IEU0 Group */; \ - add %sum, %x3, %sum /* IEU1 */; \ - fpadd32 %F14, %f14, %F14 /* FPA */; \ - fcmpgt32 %f12, %F12, %x7 /* FPM Group */; \ - subcc %len, 64, %len /* IEU1 */; \ - BRANCH /* CTI */; \ - fcmpgt32 %f14, %F14, %x8 /* FPM Group */; \ + LOAD /* Load (Group) */; \ + faligndata %A14, %F0, %A14 /* FPA Group */; \ + inc %x5 /* IEU0 */; \ + STORE1 /* Store (optional) */; \ + faligndata %F0, %F2, %A0 /* FPA Group */; \ + srl %x5, 1, %x5 /* IEU0 */; \ + add %sum, %x4, %sum /* IEU1 */; \ + fpadd32 %F0, %f0, %F0 /* FPA Group */; \ + inc %x6 /* IEU0 */; \ + STORE2 /* Store (optional) */; \ + faligndata %F2, %F4, %A2 /* FPA Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fpadd32 %F2, %f2, %F2 /* FPA Group */; \ + add %src, 64, %src /* IEU0 */; \ + fcmpgt32 %f0, %F0, %x1 /* FPM */; \ + add %dst, 64, %dst /* IEU1 Group */; \ + inc %x7 /* IEU0 */; \ + STORE3 /* Store (optional) */; \ + faligndata %F4, %F6, %A4 /* FPA */; \ + fpadd32 %F4, %f4, %F4 /* FPA Group */; \ + add %sum, %x6, %sum /* IEU1 */; \ + fcmpgt32 %f2, %F2, %x2 /* FPM */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + inc %x8 /* IEU1 */; \ + STORE4 /* Store (optional) */; \ + faligndata %F6, %F8, %A6 /* FPA */; \ + fpadd32 %F6, %f6, %F6 /* FPA Group */; \ + srl %x8, 1, %x8 /* IEU0 */; \ + fcmpgt32 %f4, %F4, %x3 /* FPM */; \ + add %sum, %x7, %sum /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + STORE5 /* Store (optional) */; \ + faligndata %F8, %F10, %A8 /* FPA */; \ + fpadd32 %F8, %f8, %F8 /* FPA Group */; \ + srl %x1, 1, %x1 /* IEU0 */; \ + fcmpgt32 %f6, %F6, %x4 /* FPM */; \ + add %sum, %x8, %sum /* IEU0 Group */; \ + inc %x2 /* IEU1 */; \ + STORE6 /* Store (optional) */; \ + faligndata %F10, %F12, %A10 /* FPA */; \ + fpadd32 %F10, %f10, %F10 /* FPA Group */; \ + srl %x2, 1, %x2 /* IEU0 */; \ + fcmpgt32 %f8, %F8, %x5 /* FPM */; \ + add %sum, %x1, %sum /* IEU0 Group */; \ + inc %x3 /* IEU1 */; \ + STORE7 /* Store (optional) */; \ + faligndata %F12, %F14, %A12 /* FPA */; \ + fpadd32 %F12, %f12, %F12 /* FPA Group */; \ + srl %x3, 1, %x3 /* IEU0 */; \ + fcmpgt32 %f10, %F10, %x6 /* FPM */; \ + add %sum, %x2, %sum /* IEU0 Group */; \ + inc %x4 /* IEU1 */; \ + STORE8 /* Store (optional) */; \ + fmovd %F14, %B14 /* FPA */; \ + fpadd32 %F14, %f14, %F14 /* FPA Group */; \ + srl %x4, 1, %x4 /* IEU0 */; \ + fcmpgt32 %f12, %F12, %x7 /* FPM */; \ + add %sum, %x3, %sum /* IEU0 Group */; \ + subcc %len, 64, %len /* IEU1 */; \ + BRANCH /* CTI */; \ + fcmpgt32 %f14, %F14, %x8 /* FPM Group */; #define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \ - inc %x5 /* IEU0 Group */; \ - fpadd32 %f2, %f0, %S0 /* FPA */; \ - srl %x5, 1, %x5 /* IEU0 Group */; \ - add %sum, %x4, %sum /* IEU1 */; \ - fpadd32 %f6, %f4, %S1 /* FPA */; \ - inc %x6 /* IEU0 Group */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fcmpgt32 %f0, %S0, %x1 /* FPM Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - inc %x7 /* IEU1 */; \ - fpadd32 %f10, %f8, %S2 /* FPA */; \ - fcmpgt32 %f4, %S1, %x2 /* FPM Group */; \ - srl %x7, 1, %x7 /* IEU0 */; \ - add %sum, %x6, %sum /* IEU1 */; \ - fpadd32 %f14, %f12, %S3 /* FPA */; \ - inc %x8 /* IEU0 Group */; \ - add %sum, %x7, %sum /* IEU1 */; \ - fzero %fz /* FPA */; \ - fcmpgt32 %f8, %S2, %x3 /* FPM Group */; \ - srl %x8, 1, %x8 /* IEU0 */; \ - inc %x1 /* IEU1 */; \ - fpadd32 %S0, %S1, %T0 /* FPA */; \ - fcmpgt32 %f12, %S3, %x4 /* FPM Group */; \ - srl %x1, 1, %x1 /* IEU0 */; \ - add %sum, %x8, %sum /* IEU1 */; \ - fpadd32 %S2, %S3, %T1 /* FPA */; \ - inc %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - fcmpgt32 %S0, %T0, %x5 /* FPM Group */; \ - srl %x2, 1, %x2 /* IEU0 */; \ - inc %x3 /* IEU1 */; \ - fcmpgt32 %S2, %T1, %x6 /* FPM Group */; \ - srl %x3, 1, %x3 /* IEU0 */; \ - add %sum, %x2, %sum /* IEU1 */; \ - inc %x4 /* IEU0 Group */; \ - add %sum, %x3, %sum /* IEU1 */; \ - fcmpgt32 %fz, %f2, %x7 /* FPM Group */; \ - srl %x4, 1, %x4 /* IEU0 */; \ - inc %x5 /* IEU1 */; \ - fpadd32 %T0, %T1, %U0 /* FPA */; \ - fcmpgt32 %fz, %f6, %x8 /* FPM Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - add %sum, %x4, %sum /* IEU1 */; \ - inc %x6 /* IEU0 Group */; \ - add %sum, %x5, %sum /* IEU1 */; \ - fcmpgt32 %fz, %f10, %x1 /* FPM Group */; \ - srl %x6, 1, %x6 /* IEU0 */; \ - inc %x7 /* IEU1 */; \ - fcmpgt32 %fz, %f14, %x2 /* FPM Group */; \ - ba,pt %xcc, ett /* CTI */; \ - fmovd %FA, %FB /* FPA */; \ + inc %x5 /* IEU0 Group */; \ + fpadd32 %f2, %f0, %S0 /* FPA */; \ + add %sum, %x4, %sum /* IEU1 */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + fpadd32 %f6, %f4, %S1 /* FPA */; \ + inc %x6 /* IEU1 */; \ + fpadd32 %f10, %f8, %S2 /* FPA Group */; \ + add %sum, %x5, %sum /* IEU0 */; \ + fcmpgt32 %f0, %S0, %x1 /* FPM */; \ + fpadd32 %f14, %f12, %S3 /* FPA Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + fcmpgt32 %f4, %S1, %x2 /* FPM */; \ + add %sum, %x6, %sum /* IEU0 Group */; \ + fzero %fz /* FPA */; \ + fcmpgt32 %f8, %S2, %x3 /* FPM */; \ + inc %x7 /* IEU0 Group */; \ + inc %x8 /* IEU1 */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + fpadd32 %S0, %S1, %T0 /* FPA */; \ + fpadd32 %S2, %S3, %T1 /* FPA Group */; \ + add %sum, %x7, %sum /* IEU0 */; \ + fcmpgt32 %f12, %S3, %x4 /* FPM */; \ + srl %x8, 1, %x8 /* IEU0 Group */; \ + inc %x2 /* IEU1 */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + add %sum, %x8, %sum /* IEU1 */; \ + add %sum, %x1, %sum /* IEU0 Group */; \ + fcmpgt32 %S0, %T0, %x5 /* FPM */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + fcmpgt32 %S2, %T1, %x6 /* FPM */; \ + inc %x3 /* IEU0 Group */; \ + add %sum, %x2, %sum /* IEU1 */; \ + srl %x3, 1, %x3 /* IEU0 Group */; \ + inc %x4 /* IEU1 */; \ + fpadd32 %T0, %T1, %U0 /* FPA Group */; \ + add %sum, %x3, %sum /* IEU0 */; \ + fcmpgt32 %fz, %f2, %x7 /* FPM */; \ + srl %x4, 1, %x4 /* IEU0 Group */; \ + fcmpgt32 %fz, %f6, %x8 /* FPM */; \ + inc %x5 /* IEU0 Group */; \ + add %sum, %x4, %sum /* IEU1 */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + fcmpgt32 %fz, %f10, %x1 /* FPM */; \ + inc %x6 /* IEU0 Group */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fmovd %FA, %FB /* FPA Group */; \ + fcmpgt32 %fz, %f14, %x2 /* FPM */; \ + srl %x6, 1, %x6 /* IEU0 Group */; \ + ba,pt %xcc, ett /* CTI */; \ + inc %x7 /* IEU1 */; -#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \ +#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \ END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62) -#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \ - fpadd32 %U0, %U1, %V0 /* FPA Group */; \ - srl %x7, 1, %x7 /* IEU0 */; \ - add %sum, %x6, %sum /* IEU1 */; \ - std %V0, [%sp + STACKOFF] /* Store Group */; \ - inc %x8 /* IEU0 */; \ - sub %sum, %x7, %sum /* IEU1 */; \ - fcmpgt32 %fz, %S1, %x3 /* FPM Group */; \ - srl %x8, 1, %x8 /* IEU0 */; \ - inc %x1 /* IEU1 */; \ - fcmpgt32 %fz, %S3, %x4 /* FPM Group */; \ - srl %x1, 1, %x1 /* IEU0 */; \ - sub %sum, %x8, %sum /* IEU1 */; \ - ldx [%sp + STACKOFF], %x8 /* Load Group */; \ - inc %x2 /* IEU0 */; \ - sub %sum, %x1, %sum /* IEU1 */; \ - fcmpgt32 %fz, %T1, %x5 /* FPM Group */; \ - srl %x2, 1, %x2 /* IEU0 */; \ - inc %x3 /* IEU1 */; \ - fcmpgt32 %T0, %U0, %x6 /* FPM Group */; \ - srl %x3, 1, %x3 /* IEU0 */; \ - sub %sum, %x2, %sum /* IEU1 */; \ - inc %x4 /* IEU0 Group */; \ - sub %sum, %x3, %sum /* IEU1 */; \ - fcmpgt32 %fz, %U1, %x7 /* FPM Group */; \ - srl %x4, 1, %x4 /* IEU0 */; \ - inc %x5 /* IEU1 */; \ - fcmpgt32 %U0, %V0, %x1 /* FPM Group */; \ - srl %x5, 1, %x5 /* IEU0 */; \ - sub %sum, %x4, %sum /* IEU1 */; \ - fcmpgt32 %fz, %V0, %x2 /* FPM Group */; \ - inc %x6 /* IEU0 */; \ - sub %sum, %x5, %sum /* IEU1 */; \ - srl %x6, 1, %x6 /* IEU0 Group */; \ - inc %x7 /* IEU1 */; \ - srl %x7, 1, %x7 /* IEU0 Group */; \ - add %sum, %x6, %sum /* IEU1 */; \ - inc %x1 /* IEU0 Group */; \ - sub %sum, %x7, %sum /* IEU1 */; \ - srl %x1, 1, %x1 /* IEU0 Group */; \ - inc %x2 /* IEU1 */; \ - srl %x2, 1, %x2 /* IEU0 Group */; \ - add %sum, %x1, %sum /* IEU1 */; \ - sub %sum, %x2, %sum /* IEU0 Group */; \ - addcc %sum, %x8, %sum /* IEU Group */; \ - bcs,a,pn %xcc, 33f /* CTI */; \ - add %sum, 1, %sum /* IEU0 */; \ -33: /* That's it */; +#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \ + fpadd32 %U0, %U1, %V0 /* FPA Group */; \ + srl %x7, 1, %x7 /* IEU0 */; \ + add %sum, %x6, %sum /* IEU1 */; \ + std %V0, [%sp + STACKOFF] /* Store Group */; \ + inc %x8 /* IEU0 */; \ + sub %sum, %x7, %sum /* IEU1 */; \ + srl %x8, 1, %x8 /* IEU0 Group */; \ + fcmpgt32 %fz, %S1, %x3 /* FPM */; \ + inc %x1 /* IEU0 Group */; \ + fcmpgt32 %fz, %S3, %x4 /* FPM */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + sub %sum, %x8, %sum /* IEU1 */; \ + ldx [%sp + STACKOFF], %x8 /* Load Group */; \ + inc %x2 /* IEU0 */; \ + sub %sum, %x1, %sum /* IEU1 */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + fcmpgt32 %fz, %T1, %x5 /* FPM */; \ + inc %x3 /* IEU0 Group */; \ + fcmpgt32 %T0, %U0, %x6 /* FPM */; \ + srl %x3, 1, %x3 /* IEU0 Group */; \ + sub %sum, %x2, %sum /* IEU1 */; \ + inc %x4 /* IEU0 Group */; \ + sub %sum, %x3, %sum /* IEU1 */; \ + srl %x4, 1, %x4 /* IEU0 Group */; \ + fcmpgt32 %fz, %U1, %x7 /* FPM */; \ + inc %x5 /* IEU0 Group */; \ + fcmpgt32 %U0, %V0, %x1 /* FPM */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + sub %sum, %x4, %sum /* IEU1 */; \ + sub %sum, %x5, %sum /* IEU0 Group */; \ + fcmpgt32 %fz, %V0, %x2 /* FPM */; \ + inc %x6 /* IEU0 Group */; \ + inc %x7 /* IEU1 */; \ + srl %x6, 1, %x6 /* IEU0 Group */; \ + inc %x1 /* IEU1 */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + add %sum, %x6, %sum /* IEU1 */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + sub %sum, %x7, %sum /* IEU1 */; \ + inc %x2 /* IEU0 Group */; \ + add %sum, %x1, %sum /* IEU1 */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + sub %sum, %x2, %sum /* IEU0 Group */; \ + addcc %sum, %x8, %sum /* IEU1 Group */; \ + bcs,a,pn %xcc, 33f /* CTI */; \ + add %sum, 1, %sum /* IEU0 (Group) */; \ +33: /* That's it */; .text .globl csum_partial_copy_user_vis .align 32 -/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp. csum_partial_copy_from_user */ -/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */ +/* %asi should be either ASI_P or ASI_AIUS for csum_partial_copy resp. + * csum_partial_copy_from_user + * This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 + */ csum_partial_copy_user_vis: - andcc %dst, 7, %g0 /* IEU1 Group */ - be,pt %icc, 4f /* CTI */ - and %dst, 0x38, %o4 /* IEU0 */ - mov 1, %g5 /* IEU0 Group */ - andcc %dst, 2, %g0 /* IEU1 */ - be,pt %icc, 1f /* CTI */ - and %dst, 4, %g7 /* IEU0 Group */ - lduh [%src], %g2 /* Load */ - sub %len, 2, %len /* IEU0 Group */ - add %dst, 2, %dst /* IEU1 */ - andcc %dst, 4, %g7 /* IEU1 Group */ - sll %g5, 16, %g5 /* IEU0 */ - stha %g2, [%dst - 2] %asi /* Store Group */ - sll %g2, 16, %g2 /* IEU0 */ - add %src, 2, %src /* IEU1 */ - addcc %g2, %sum, %sum /* IEU1 Group */ - bcs,a,pn %icc, 1f /* CTI */ - add %sum, %g5, %sum /* IEU0 */ -1: lduw [%src], %g2 /* Load */ - brz,a,pn %g7, 4f /* CTI+IEU1 Group */ - and %dst, 0x38, %o4 /* IEU0 */ - add %dst, 4, %dst /* IEU0 Group */ - sub %len, 4, %len /* IEU1 */ - addcc %g2, %sum, %sum /* IEU1 Group */ - bcs,a,pn %icc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: and %dst, 0x38, %o4 /* IEU0 Group */ - stwa %g2, [%dst - 4] %asi /* Store */ - add %src, 4, %src /* IEU1 */ + andcc %dst, 7, %g0 /* IEU1 Group */ + be,pt %icc, 4f /* CTI */ + and %dst, 0x38, %o4 /* IEU0 */ + mov 1, %g5 /* IEU0 Group */ + andcc %dst, 2, %g0 /* IEU1 */ + be,pt %icc, 1f /* CTI */ + and %dst, 4, %g7 /* IEU0 Group */ + lduh [%src], %g2 /* Load */ + sub %len, 2, %len /* IEU0 Group */ + add %dst, 2, %dst /* IEU1 */ + andcc %dst, 4, %g7 /* IEU1 Group */ + sll %g5, 16, %g5 /* IEU0 */ + stha %g2, [%dst - 2] %asi /* Store Group */ + sll %g2, 16, %g2 /* IEU0 */ + add %src, 2, %src /* IEU1 */ + addcc %g2, %sum, %sum /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %sum, %g5, %sum /* IEU0 */ +1: lduw [%src], %g2 /* Load */ + brz,a,pn %g7, 4f /* CTI+IEU1 Group */ + and %dst, 0x38, %o4 /* IEU0 */ + add %dst, 4, %dst /* IEU0 Group */ + sub %len, 4, %len /* IEU1 */ + addcc %g2, %sum, %sum /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: and %dst, 0x38, %o4 /* IEU0 Group */ + stwa %g2, [%dst - 4] %asi /* Store */ + add %src, 4, %src /* IEU1 */ 4: #ifdef __KERNEL__ VISEntry #endif - mov %src, %g7 /* IEU1 Group */ - fzero %f48 /* FPA */ - alignaddr %src, %g0, %src /* Single Group */ - subcc %g7, %src, %g7 /* IEU1 Group */ - be,pt %xcc, 1f /* CTI */ - mov 0x40, %g1 /* IEU0 */ - lduw [%src], %g2 /* Load Group */ - subcc %sum, %g2, %sum /* IEU1 Group+load stall */ - bcs,a,pn %icc, 1f /* CTI */ - sub %sum, 1, %sum /* IEU0 */ -1: srl %sum, 0, %sum /* IEU0 Group */ - clr %g5 /* IEU1 */ - brz,pn %o4, 3f /* CTI+IEU1 Group */ - sub %g1, %o4, %g1 /* IEU0 */ - ldd [%src], %f0 /* Load */ - clr %o4 /* IEU0 Group */ - andcc %dst, 8, %g0 /* IEU1 */ - be,pn %icc, 1f /* CTI */ - ldd [%src + 8], %f2 /* Load Group */ - add %src, 8, %src /* IEU0 */ - sub %len, 8, %len /* IEU1 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - addcc %dst, 8, %dst /* IEU1 Group */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %o4 /* FPM Group */ - fmovd %f2, %f0 /* FPA Group */ - ldd [%src + 8], %f2 /* Load */ - stda %f16, [%dst - 8] %asi /* Store */ - fmovd %f50, %f48 /* FPA */ -1: andcc %g1, 0x10, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - and %g1, 0x20, %g1 /* IEU0 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - ldd [%src + 16], %f4 /* Load Group */ - add %src, 16, %src /* IEU0 */ - add %dst, 16, %dst /* IEU1 */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %g5 /* FPM Group */ - sub %len, 16, %len /* IEU0 */ - inc %o4 /* IEU1 */ - stda %f16, [%dst - 16] %asi /* Store Group */ - fpadd32 %f2, %f50, %f48 /* FPA */ - srl %o4, 1, %o5 /* IEU0 */ - faligndata %f2, %f4, %f18 /* FPA Group */ - stda %f18, [%dst - 8] %asi /* Store */ - fcmpgt32 %f50, %f48, %o4 /* FPM Group */ - add %o5, %sum, %sum /* IEU0 */ - ldd [%src + 8], %f2 /* Load */ - fmovd %f4, %f0 /* FPA */ -1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */ - rd %asi, %g2 /* LSU Group + 4 bubbles */ - inc %g5 /* IEU0 */ - fpadd32 %f0, %f48, %f50 /* FPA */ - ldd [%src + 16], %f4 /* Load Group */ - srl %g5, 1, %g5 /* IEU0 */ - add %dst, 32, %dst /* IEU1 */ - faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %o5 /* FPM Group */ - inc %o4 /* IEU0 */ - ldd [%src + 24], %f6 /* Load */ - srl %o4, 1, %o4 /* IEU0 Group */ - add %g5, %sum, %sum /* IEU1 */ - ldd [%src + 32], %f8 /* Load */ - fpadd32 %f2, %f50, %f48 /* FPA */ - faligndata %f2, %f4, %f18 /* FPA Group */ - sub %len, 32, %len /* IEU0 */ - stda %f16, [%dst - 32] %asi /* Store */ - fcmpgt32 %f50, %f48, %g3 /* FPM Group */ - inc %o5 /* IEU0 */ - add %o4, %sum, %sum /* IEU1 */ - fpadd32 %f4, %f48, %f50 /* FPA */ - faligndata %f4, %f6, %f20 /* FPA Group */ - srl %o5, 1, %o5 /* IEU0 */ - fcmpgt32 %f48, %f50, %g5 /* FPM Group */ - add %o5, %sum, %sum /* IEU0 */ - stda %f18, [%dst - 24] %asi /* Store */ - fpadd32 %f6, %f50, %f48 /* FPA */ - inc %g3 /* IEU0 Group */ - stda %f20, [%dst - 16] %asi /* Store */ - add %src, 32, %src /* IEU1 */ - faligndata %f6, %f8, %f22 /* FPA */ - fcmpgt32 %f50, %f48, %o4 /* FPM Group */ - srl %g3, 1, %g3 /* IEU0 */ - stda %f22, [%dst - 8] %asi /* Store */ - add %g3, %sum, %sum /* IEU0 Group */ -3: rd %asi, %g2 /* LSU Group + 4 bubbles */ + mov %src, %g7 /* IEU1 Group */ + fzero %f48 /* FPA */ + alignaddr %src, %g0, %src /* Single Group */ + subcc %g7, %src, %g7 /* IEU1 Group */ + be,pt %xcc, 1f /* CTI */ + mov 0x40, %g1 /* IEU0 */ + lduw [%src], %g2 /* Load Group */ + subcc %sum, %g2, %sum /* IEU1 Group+load stall*/ + bcs,a,pn %icc, 1f /* CTI */ + sub %sum, 1, %sum /* IEU0 */ +1: srl %sum, 0, %sum /* IEU0 Group */ + clr %g5 /* IEU1 */ + brz,pn %o4, 3f /* CTI+IEU1 Group */ + sub %g1, %o4, %g1 /* IEU0 */ + ldd [%src], %f0 /* Load */ + clr %o4 /* IEU0 Group */ + andcc %dst, 8, %g0 /* IEU1 */ + be,pn %icc, 1f /* CTI */ + ldd [%src + 8], %f2 /* Load Group */ + add %src, 8, %src /* IEU0 */ + sub %len, 8, %len /* IEU1 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + addcc %dst, 8, %dst /* IEU1 Group */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %o4 /* FPM Group */ + fmovd %f2, %f0 /* FPA Group */ + ldd [%src + 8], %f2 /* Load */ + stda %f16, [%dst - 8] %asi /* Store */ + fmovd %f50, %f48 /* FPA */ +1: andcc %g1, 0x10, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + and %g1, 0x20, %g1 /* IEU0 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + ldd [%src + 16], %f4 /* Load Group */ + add %src, 16, %src /* IEU0 */ + add %dst, 16, %dst /* IEU1 */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %g5 /* FPM Group */ + sub %len, 16, %len /* IEU0 */ + inc %o4 /* IEU1 */ + stda %f16, [%dst - 16] %asi /* Store Group */ + fpadd32 %f2, %f50, %f48 /* FPA */ + srl %o4, 1, %o5 /* IEU0 */ + faligndata %f2, %f4, %f18 /* FPA Group */ + stda %f18, [%dst - 8] %asi /* Store */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + add %o5, %sum, %sum /* IEU0 */ + ldd [%src + 8], %f2 /* Load */ + fmovd %f4, %f0 /* FPA */ +1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */ + rd %asi, %g2 /* LSU Group + 4 bubbles*/ + inc %g5 /* IEU0 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + ldd [%src + 16], %f4 /* Load Group */ + srl %g5, 1, %g5 /* IEU0 */ + add %dst, 32, %dst /* IEU1 */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %o5 /* FPM Group */ + inc %o4 /* IEU0 */ + ldd [%src + 24], %f6 /* Load */ + srl %o4, 1, %o4 /* IEU0 Group */ + add %g5, %sum, %sum /* IEU1 */ + ldd [%src + 32], %f8 /* Load */ + fpadd32 %f2, %f50, %f48 /* FPA */ + faligndata %f2, %f4, %f18 /* FPA Group */ + sub %len, 32, %len /* IEU0 */ + stda %f16, [%dst - 32] %asi /* Store */ + fcmpgt32 %f50, %f48, %g3 /* FPM Group */ + inc %o5 /* IEU0 */ + add %o4, %sum, %sum /* IEU1 */ + fpadd32 %f4, %f48, %f50 /* FPA */ + faligndata %f4, %f6, %f20 /* FPA Group */ + srl %o5, 1, %o5 /* IEU0 */ + fcmpgt32 %f48, %f50, %g5 /* FPM Group */ + add %o5, %sum, %sum /* IEU0 */ + stda %f18, [%dst - 24] %asi /* Store */ + fpadd32 %f6, %f50, %f48 /* FPA */ + inc %g3 /* IEU0 Group */ + stda %f20, [%dst - 16] %asi /* Store */ + add %src, 32, %src /* IEU1 */ + faligndata %f6, %f8, %f22 /* FPA */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + srl %g3, 1, %g3 /* IEU0 */ + stda %f22, [%dst - 8] %asi /* Store */ + add %g3, %sum, %sum /* IEU0 Group */ +3: rd %asi, %g2 /* LSU Group + 4 bubbles*/ #ifdef __KERNEL__ -4: sethi %hi(vis0s), %g7 /* IEU0 Group */ - or %g2, ASI_BLK_OR, %g2 /* IEU1 */ +4: sethi %hi(vis0s), %g7 /* IEU0 Group */ + or %g2, ASI_BLK_OR, %g2 /* IEU1 */ #else -4: rd %pc, %g7 /* LSU Group + 4 bubbles */ +4: rd %pc, %g7 /* LSU Group + 4 bubbles*/ #endif - inc %g5 /* IEU0 Group */ - and %src, 0x38, %g3 /* IEU1 */ - membar #StoreLoad /* LSU Group */ - srl %g5, 1, %g5 /* IEU0 */ - inc %o4 /* IEU1 */ - sll %g3, 8, %g3 /* IEU0 Group */ - sub %len, 0xc0, %len /* IEU1 */ - addcc %g5, %sum, %sum /* IEU1 Group */ - srl %o4, 1, %o4 /* IEU0 */ - add %g7, %g3, %g7 /* IEU0 Group */ - add %o4, %sum, %sum /* IEU1 */ + inc %g5 /* IEU0 Group */ + and %src, 0x38, %g3 /* IEU1 */ + membar #StoreLoad /* LSU Group */ + srl %g5, 1, %g5 /* IEU0 */ + inc %o4 /* IEU1 */ + sll %g3, 8, %g3 /* IEU0 Group */ + sub %len, 0xc0, %len /* IEU1 */ + addcc %g5, %sum, %sum /* IEU1 Group */ + srl %o4, 1, %o4 /* IEU0 */ + add %g7, %g3, %g7 /* IEU0 Group */ + add %o4, %sum, %sum /* IEU1 */ #ifdef __KERNEL__ - jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */ + jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */ #else - jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */ + jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */ #endif - fzero %f32 /* FPA */ + fzero %f32 /* FPA */ .align 2048 -vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src] ASI_BLK_P, %f0 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f48, %f62 /* FPA Group f0 available */ - faligndata %f0, %f2, %f48 /* FPA Group f2 available */ - fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available */ - fpadd32 %f0, %f62, %f0 /* FPA */ - fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available */ - faligndata %f2, %f4, %f50 /* FPA */ - fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available */ - faligndata %f4, %f6, %f52 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available */ - inc %x1 /* IEU0 */ - faligndata %f6, %f8, %f54 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available */ - srl %x1, 1, %x1 /* IEU0 */ - inc %x2 /* IEU1 */ - faligndata %f8, %f10, %f56 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available */ - srl %x2, 1, %x2 /* IEU0 */ - add %sum, %x1, %sum /* IEU1 */ - faligndata %f10, %f12, %f58 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - add %sum, %x2, %sum /* IEU1 */ - faligndata %f12, %f14, %f60 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f62 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src] ASI_BLK_P, %f0 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f48, %f62 /* FPA Group f0 available*/ + faligndata %f0, %f2, %f48 /* FPA Group f2 available*/ + fcmpgt32 %f32, %f2, %x1 /* FPM Group f4 available*/ + fpadd32 %f0, %f62, %f0 /* FPA */ + fcmpgt32 %f32, %f4, %x2 /* FPM Group f6 available*/ + faligndata %f2, %f4, %f50 /* FPA */ + fcmpgt32 %f62, %f0, %x3 /* FPM Group f8 available*/ + faligndata %f4, %f6, %f52 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group f10 available*/ + inc %x1 /* IEU0 */ + faligndata %f6, %f8, %f54 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group f12 available*/ + srl %x1, 1, %x1 /* IEU0 */ + inc %x2 /* IEU1 */ + faligndata %f8, %f10, %f56 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group f14 available*/ + srl %x2, 1, %x2 /* IEU0 */ + add %sum, %x1, %sum /* IEU1 */ + faligndata %f10, %f12, %f58 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + add %sum, %x2, %sum /* IEU1 */ + faligndata %f12, %f14, %f60 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f62 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis0: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f48,f50,f52,f54,f56,f58,f60,f62,f62, ,LDBLK(f32), STBLK,,,,,,,, @@ -468,36 +470,36 @@ ,SYNC, STBLK_XORASI(x1,x2),ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1) .align 2048 -vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - sub %src, 8, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f0 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f0, %f58 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - fcmpgt32 %f32, %f2, %x2 /* FPM Group */ - faligndata %f2, %f4, %f48 /* FPA */ - fcmpgt32 %f32, %f4, %x3 /* FPM Group */ - faligndata %f4, %f6, %f50 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f52 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - inc %x2 /* IEU1 */ - faligndata %f8, %f10, %f54 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - srl %x2, 1, %x2 /* IEU0 */ - faligndata %f10, %f12, %f56 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - add %sum, %x2, %sum /* IEU1 */ - faligndata %f12, %f14, %f58 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f60 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + sub %src, 8, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f0 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f0, %f58 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + fcmpgt32 %f32, %f2, %x2 /* FPM Group */ + faligndata %f2, %f4, %f48 /* FPA */ + fcmpgt32 %f32, %f4, %x3 /* FPM Group */ + faligndata %f4, %f6, %f50 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f52 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + inc %x2 /* IEU1 */ + faligndata %f8, %f10, %f54 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + srl %x2, 1, %x2 /* IEU0 */ + faligndata %f10, %f12, %f56 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + add %sum, %x2, %sum /* IEU1 */ + faligndata %f12, %f14, %f58 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f60 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis1: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f62,f48,f50,f52,f54,f56,f58,f60,f60, ,LDBLK(f32), ,STBLK,,,,,,, @@ -523,33 +525,33 @@ ,SYNC, ,STBLK_XORASI(x1,x2),ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40), ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1) .align 2048 -vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - sub %src, 16, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f0 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f0, %f56 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fcmpgt32 %f32, %f4, %x3 /* FPM Group */ - faligndata %f4, %f6, %f48 /* FPA */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f50 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f52 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f54 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - inc %x3 /* IEU0 */ - faligndata %f12, %f14, %f56 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - srl %x3, 1, %x3 /* IEU0 */ - inc %x4 /* IEU1 */ - fmovd %f14, %f58 /* FPA */ - srl %x4, 1, %x4 /* IEU0 Group */ - add %sum, %x3, %sum /* IEU1 */ +vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + sub %src, 16, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f0 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f0, %f56 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fcmpgt32 %f32, %f4, %x3 /* FPM Group */ + faligndata %f4, %f6, %f48 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f50 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f52 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f54 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + faligndata %f12, %f14, %f56 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f58 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ vis2: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f60,f62,f48,f50,f52,f54,f56,f58,f58, ,LDBLK(f32), ,,STBLK,,,,,, @@ -575,29 +577,29 @@ ,SYNC, ,,STBLK_XORASI(x2,x3),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96), ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1) .align 2048 -vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - sub %src, 24, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f0 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f0, %f54 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fpsub32 %f4, %f4, %f4 /* FPA Group */ - fcmpgt32 %f32, %f6, %x4 /* FPM Group */ - faligndata %f6, %f8, %f48 /* FPA */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f50 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f52 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f54 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f56 /* FPA */ - inc %x4 /* IEU0 */ - srl %x4, 1, %x4 /* IEU0 Group */ +vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + sub %src, 24, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f0 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f0, %f54 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fpsub32 %f4, %f4, %f4 /* FPA Group */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f48 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f50 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f52 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f54 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f56 /* FPA */ + inc %x4 /* IEU0 */ + srl %x4, 1, %x4 /* IEU0 Group */ vis3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f58,f60,f62,f48,f50,f52,f54,f56,f56, ,LDBLK(f32), ,,,STBLK,,,,, @@ -623,27 +625,27 @@ ,SYNC, ,,,STBLK_XORASI(x3,x4),ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88), ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1) .align 2048 -vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - sub %src, 32, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f0 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f0, %f52 /* FPA Group */ - fmovd %f48, %f0 /* FPA Group */ - sub %dst, 64, %dst /* IEU0 */ - fpsub32 %f2, %f2, %f2 /* FPA Group */ - fpsub32 %f4, %f4, %f4 /* FPA Group */ - fpsub32 %f6, %f6, %f6 /* FPA Group */ - clr %x4 /* IEU0 */ - fcmpgt32 %f32, %f8, %x5 /* FPM Group */ - faligndata %f8, %f10, %f48 /* FPA */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - faligndata %f10, %f12, %f50 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f52 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f54 /* FPA */ +vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + sub %src, 32, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f0 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f0, %f52 /* FPA Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fpsub32 %f2, %f2, %f2 /* FPA Group */ + fpsub32 %f4, %f4, %f4 /* FPA Group */ + fpsub32 %f6, %f6, %f6 /* FPA Group */ + clr %x4 /* IEU0 */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f48 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f50 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f52 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f54 /* FPA */ vis4: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f56,f58,f60,f62,f48,f50,f52,f54,f54, ,LDBLK(f32), ,,,,STBLK,,,, @@ -669,27 +671,27 @@ ,SYNC, ,,,,STBLK_XORASI(x4,x5),ST(f48,64),ST(f50,72),ST(f52,80), ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1) .align 2048 -vis5s: ldd [%src+0], %f10 /* Load Group */ - ldd [%src+8], %f12 /* Load Group */ - ldd [%src+16], %f14 /* Load Group */ - add %src, 24, %src /* IEU0 Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fcmpgt32 %f32, %f10, %x6 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - faligndata %f10, %f12, %f48 /* FPA */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - faligndata %f12, %f14, %f50 /* FPA */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - fmovd %f14, %f52 /* FPA */ +vis5s: ldd [%src+0], %f10 /* Load Group */ + ldd [%src+8], %f12 /* Load Group */ + ldd [%src+16], %f14 /* Load Group */ + add %src, 24, %src /* IEU0 Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + faligndata %f10, %f12, %f48 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f50 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f52 /* FPA */ vis5: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f54,f56,f58,f60,f62,f48,f50,f52,f52, ,LDBLK(f32), ,,,,,STBLK,,, @@ -715,26 +717,26 @@ ,SYNC, ,,,,,STBLK_XORASI(x5,x6),ST(f48,64),ST(f50,72), ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1) .align 2048 -vis6s: ldd [%src+0], %f12 /* Load Group */ - ldd [%src+8], %f14 /* Load Group */ - add %src, 16, %src /* IEU0 Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fmuld %f32, %f32, %f10 /* FPM */ - clr %x6 /* IEU0 */ - fcmpgt32 %f32, %f12, %x7 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - faligndata %f12, %f14, %f48 /* FPA */ - fmovd %f14, %f50 /* FPA Group */ +vis6s: ldd [%src+0], %f12 /* Load Group */ + ldd [%src+8], %f14 /* Load Group */ + add %src, 16, %src /* IEU0 Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fmuld %f32, %f32, %f10 /* FPM */ + clr %x6 /* IEU0 */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + faligndata %f12, %f14, %f48 /* FPA */ + fmovd %f14, %f50 /* FPA Group */ vis6: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f52,f54,f56,f58,f60,f62,f48,f50,f50, ,LDBLK(f32), ,,,,,,STBLK,, @@ -760,25 +762,25 @@ ,SYNC, ,,,,,,STBLK_XORASI(x6,x7),ST(f48,64), ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1) .align 2048 -vis7s: ldd [%src+0], %f14 /* Load Group */ - add %src, 8, %src /* IEU0 Group */ - wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ - ldda [%src] ASI_BLK_P, %f16 /* Load Group */ - add %src, 64, %src /* IEU0 Group */ - fmovd %f48, %f0 /* FPA Group */ - fmuld %f32, %f32, %f2 /* FPM */ - clr %x4 /* IEU0 */ - faddd %f32, %f32, %f4 /* FPA Group */ - fmuld %f32, %f32, %f6 /* FPM */ - clr %x5 /* IEU0 */ - faddd %f32, %f32, %f8 /* FPA Group */ - fmuld %f32, %f32, %f10 /* FPM */ - clr %x6 /* IEU0 */ - faddd %f32, %f32, %f12 /* FPA Group */ - clr %x7 /* IEU0 */ - fcmpgt32 %f32, %f14, %x8 /* FPM Group */ - sub %dst, 64, %dst /* IEU0 */ - fmovd %f14, %f48 /* FPA */ +vis7s: ldd [%src+0], %f14 /* Load Group */ + add %src, 8, %src /* IEU0 Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src] ASI_BLK_P, %f16 /* Load Group */ + add %src, 64, %src /* IEU0 Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fmuld %f32, %f32, %f10 /* FPM */ + clr %x6 /* IEU0 */ + faddd %f32, %f32, %f12 /* FPA Group */ + clr %x7 /* IEU0 */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + fmovd %f14, %f48 /* FPA */ vis7: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, ,f50,f52,f54,f56,f58,f60,f62,f48,f48, ,LDBLK(f32), ,,,,,,,STBLK, @@ -806,104 +808,104 @@ e1: END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6) e2: END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6) e3: END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6) -ett: rd %gsr, %x3 /* LSU Group+4bubbles */ - andcc %x3, 7, %x3 /* IEU1 Group */ - add %dst, 8, %dst /* IEU0 */ - bne,pn %icc, 1f /* CTI */ - fzero %f10 /* FPA */ - brz,a,pn %len, 2f /* CTI+IEU1 Group */ - stda %f6, [%dst - 8] %asi /* Store */ -1: cmp %len, 8 /* IEU1 */ - blu,pn %icc, 3f /* CTI */ - sub %src, 64, %src /* IEU0 Group */ -1: ldd [%src], %f2 /* Load Group */ - fpadd32 %f10, %f2, %f12 /* FPA Group+load stall */ - add %src, 8, %src /* IEU0 */ - add %dst, 8, %dst /* IEU1 */ - faligndata %f6, %f2, %f14 /* FPA Group */ - fcmpgt32 %f10, %f12, %x5 /* FPM Group */ - stda %f14, [%dst - 16] %asi /* Store */ - fmovd %f2, %f6 /* FPA */ - fmovd %f12, %f10 /* FPA Group */ - sub %len, 8, %len /* IEU1 */ - fzero %f16 /* FPA Group - FPU nop */ - fzero %f18 /* FPA Group - FPU nop */ - inc %x5 /* IEU0 */ - srl %x5, 1, %x5 /* IEU0 Group (regdep) */ - cmp %len, 8 /* IEU1 */ - bgeu,pt %icc, 1b /* CTI */ - add %x5, %sum, %sum /* IEU0 Group */ -3: brz,a,pt %x3, 2f /* CTI+IEU1 */ - stda %f6, [%dst - 8] %asi /* Store Group */ - sta %f7, [%dst - 8] %asi /* Store Group */ - sub %dst, 4, %dst /* IEU0 */ - add %len, 4, %len /* IEU1 */ +ett: rd %gsr, %x3 /* LSU Group+4bubbles */ + andcc %x3, 7, %x3 /* IEU1 Group */ + add %dst, 8, %dst /* IEU0 */ + bne,pn %icc, 1f /* CTI */ + fzero %f10 /* FPA */ + brz,a,pn %len, 2f /* CTI+IEU1 Group */ + stda %f6, [%dst - 8] %asi /* Store */ +1: cmp %len, 8 /* IEU1 */ + blu,pn %icc, 3f /* CTI */ + sub %src, 64, %src /* IEU0 Group */ +1: ldd [%src], %f2 /* Load Group */ + fpadd32 %f10, %f2, %f12 /* FPA Group+load stall*/ + add %src, 8, %src /* IEU0 */ + add %dst, 8, %dst /* IEU1 */ + faligndata %f6, %f2, %f14 /* FPA Group */ + fcmpgt32 %f10, %f12, %x5 /* FPM Group */ + stda %f14, [%dst - 16] %asi /* Store */ + fmovd %f2, %f6 /* FPA */ + fmovd %f12, %f10 /* FPA Group */ + sub %len, 8, %len /* IEU1 */ + fzero %f16 /* FPA Group - FPU nop */ + fzero %f18 /* FPA Group - FPU nop */ + inc %x5 /* IEU0 */ + srl %x5, 1, %x5 /* IEU0 Group (regdep) */ + cmp %len, 8 /* IEU1 */ + bgeu,pt %icc, 1b /* CTI */ + add %x5, %sum, %sum /* IEU0 Group */ +3: brz,a,pt %x3, 2f /* CTI+IEU1 */ + stda %f6, [%dst - 8] %asi /* Store Group */ + sta %f7, [%dst - 8] %asi /* Store Group */ + sub %dst, 4, %dst /* IEU0 */ + add %len, 4, %len /* IEU1 */ 2: #ifdef __KERNEL__ - sub %sp, 8, %sp /* IEU0 Group */ + sub %sp, 8, %sp /* IEU0 Group */ #endif END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62) - membar #Sync /* LSU Group */ + membar #Sync /* LSU Group */ #ifdef __KERNEL__ VISExit - add %sp, 8, %sp /* IEU0 Group */ + add %sp, 8, %sp /* IEU0 Group */ #endif -23: brnz,pn %len, 26f /* CTI+IEU1 Group */ -24: sllx %sum, 32, %g1 /* IEU0 */ -25: addcc %sum, %g1, %src /* IEU1 Group */ - srlx %src, 32, %src /* IEU0 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %src, 1, %src /* IEU1 */ +23: brnz,pn %len, 26f /* CTI+IEU1 Group */ +24: sllx %sum, 32, %g1 /* IEU0 */ +25: addcc %sum, %g1, %src /* IEU1 Group */ + srlx %src, 32, %src /* IEU0 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %src, 1, %src /* IEU1 */ #ifndef __KERNEL__ -1: retl /* CTI Group brk forced */ - srl %src, 0, %src /* IEU0 */ +1: retl /* CTI Group brk forced*/ + srl %src, 0, %src /* IEU0 */ #else -1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */ - retl /* CTI Group brk forced */ - sllx %g4, 32, %g4 /* IEU0 */ +1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */ + retl /* CTI Group brk forced*/ + sllx %g4, 32, %g4 /* IEU0 */ #endif -26: andcc %len, 8, %g0 /* IEU1 Group */ - be,pn %icc, 1f /* CTI */ - lduw [%src], %o4 /* Load */ - lduw [%src+4], %g2 /* Load Group */ - add %src, 8, %src /* IEU0 */ - add %dst, 8, %dst /* IEU1 */ - sllx %o4, 32, %g5 /* IEU0 Group */ - stwa %o4, [%dst - 8] %asi /* Store */ - or %g5, %g2, %g5 /* IEU0 Group */ - stwa %g2, [%dst - 4] %asi /* Store */ - addcc %g5, %sum, %sum /* IEU1 Group */ - bcs,a,pn %xcc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: andcc %len, 4, %g0 /* IEU1 Group */ - be,a,pn %icc, 1f /* CTI */ - clr %g2 /* IEU0 */ - lduw [%src], %g7 /* Load */ - add %src, 4, %src /* IEU0 Group */ - add %dst, 4, %dst /* IEU1 */ - sllx %g7, 32, %g2 /* IEU0 Group */ - stwa %g7, [%dst - 4] %asi /* Store */ -1: andcc %len, 2, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %g3 /* IEU0 Group */ - lduh [%src], %g7 /* Load */ - add %src, 2, %src /* IEU1 */ - add %dst, 2, %dst /* IEU0 Group */ - sll %g7, 16, %g3 /* IEU0 Group */ - stha %g7, [%dst - 2] %asi /* Store */ -1: andcc %len, 1, %g0 /* IEU1 */ - be,a,pn %icc, 1f /* CTI */ - clr %o5 /* IEU0 Group */ - ldub [%src], %g7 /* Load */ - sll %g7, 8, %o5 /* IEU0 Group */ - stba %g7, [%dst] %asi /* Store */ -1: or %g2, %g3, %g3 /* IEU1 */ - or %o5, %g3, %g3 /* IEU0 Group (regdep) */ - addcc %g3, %sum, %sum /* IEU1 Group (regdep) */ - bcs,a,pn %xcc, 1f /* CTI */ - add %sum, 1, %sum /* IEU0 */ -1: ba,pt %xcc, 25b /* CTI Group */ - sllx %sum, 32, %g1 /* IEU0 */ +26: andcc %len, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + lduw [%src], %o4 /* Load */ + lduw [%src+4], %g2 /* Load Group */ + add %src, 8, %src /* IEU0 */ + add %dst, 8, %dst /* IEU1 */ + sllx %o4, 32, %g5 /* IEU0 Group */ + stwa %o4, [%dst - 8] %asi /* Store */ + or %g5, %g2, %g5 /* IEU0 Group */ + stwa %g2, [%dst - 4] %asi /* Store */ + addcc %g5, %sum, %sum /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: andcc %len, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + lduw [%src], %g7 /* Load */ + add %src, 4, %src /* IEU0 Group */ + add %dst, 4, %dst /* IEU1 */ + sllx %g7, 32, %g2 /* IEU0 Group */ + stwa %g7, [%dst - 4] %asi /* Store */ +1: andcc %len, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %g3 /* IEU0 Group */ + lduh [%src], %g7 /* Load */ + add %src, 2, %src /* IEU1 */ + add %dst, 2, %dst /* IEU0 Group */ + sll %g7, 16, %g3 /* IEU0 Group */ + stha %g7, [%dst - 2] %asi /* Store */ +1: andcc %len, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + ldub [%src], %g7 /* Load */ + sll %g7, 8, %o5 /* IEU0 Group */ + stba %g7, [%dst] %asi /* Store */ +1: or %g2, %g3, %g3 /* IEU1 */ + or %o5, %g3, %g3 /* IEU0 Group (regdep) */ + addcc %g3, %sum, %sum /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %sum, 32, %g1 /* IEU0 */ #ifdef __KERNEL__ end: diff -u --recursive --new-file v2.3.47/linux/drivers/Makefile linux/drivers/Makefile --- v2.3.47/linux/drivers/Makefile Sun Feb 20 21:12:38 2000 +++ linux/drivers/Makefile Fri Feb 25 10:26:42 2000 @@ -57,6 +57,11 @@ MOD_SUB_DIRS += macintosh endif +ifdef CONFIG_PPC +SUB_DIRS += macintosh +MOD_SUB_DIRS += macintosh +endif + ifeq ($(CONFIG_USB),y) SUB_DIRS += usb MOD_SUB_DIRS += usb @@ -75,7 +80,7 @@ endif endif -ifdef CONFIG_SGI +ifdef CONFIG_SGI_IP22 SUB_DIRS += sgi MOD_SUB_DIRS += sgi endif diff -u --recursive --new-file v2.3.47/linux/drivers/atm/Config.in linux/drivers/atm/Config.in --- v2.3.47/linux/drivers/atm/Config.in Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/Config.in Mon Feb 21 16:32:27 2000 @@ -51,4 +51,29 @@ bool ' Enable debugging messages' CONFIG_ATM_IA_DEBUG fi fi +if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SBUS" = "y" ]; then + tristate 'FORE Systems 200E-series' CONFIG_ATM_FORE200E + if [ "$CONFIG_ATM_FORE200E" != "n" ]; then + if [ "$CONFIG_PCI" = "y" ]; then + bool ' PCA-200E support' CONFIG_ATM_FORE200E_PCA y + if [ "$CONFIG_ATM_FORE200E_PCA" = "y" ]; then + bool ' Use default PCA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_PCA_DEFAULT_FW + if [ "$CONFIG_ATM_FORE200E_PCA_DEFAULT_FW" = "n" ]; then + string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_PCA_FW + fi + fi + fi + if [ "$CONFIG_SBUS" = "y" ]; then + bool ' SBA-200E support' CONFIG_ATM_FORE200E_SBA y + if [ "$CONFIG_ATM_FORE200E_SBA" = "y" ]; then + bool ' Use default SBA-200E firmware (normally enabled)' CONFIG_ATM_FORE200E_SBA_DEFAULT_FW + if [ "$CONFIG_ATM_FORE200E_SBA_DEFAULT_FW" = "n" ]; then + string ' Pathname of user-supplied binary firmware' CONFIG_ATM_FORE200E_SBA_FW "" + fi + fi + fi + int ' Maximum number of tx retries' CONFIG_ATM_FORE200E_TX_RETRY 16 + int ' Debugging level (0-3)' CONFIG_ATM_FORE200E_DEBUG 0 + fi +fi endmenu diff -u --recursive --new-file v2.3.47/linux/drivers/atm/Makefile linux/drivers/atm/Makefile --- v2.3.47/linux/drivers/atm/Makefile Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/Makefile Mon Feb 21 16:32:27 2000 @@ -100,6 +100,58 @@ LX_OBJS += $(NEED_IDT77105_LX) endif +ifeq ($(CONFIG_ATM_FORE200E_PCA),y) +FORE200E_FW_OBJS += fore200e_pca_fw.o + ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y) +# guess the target endianess to choose the right PCA-200E firmware image + CONFIG_ATM_FORE200E_PCA_FW := $(shell if test -n "`$(CC) -E -dM ../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo pca200e.bin; else echo pca200e_ecd.bin2; fi) + endif +endif +ifeq ($(CONFIG_ATM_FORE200E_SBA),y) +FORE200E_FW_OBJS += fore200e_sba_fw.o + ifeq ($(CONFIG_ATM_FORE200E_SBA_DEFAULT_FW),y) + CONFIG_ATM_FORE200E_SBA_FW := sba200e_ecd.bin2 + endif +endif +ifeq ($(CONFIG_ATM_FORE200E),y) +L_OBJS += fore200e.o $(FORE200E_FW_OBJS) +else + ifeq ($(CONFIG_ATM_FORE200E),m) + M_OBJS += fore_200e.o + endif +endif + EXTRA_CFLAGS=-g include $(TOPDIR)/Rules.make + +# FORE Systems 200E-series firmware magic +fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \ + fore200e_mkfirm + ./fore200e_mkfirm -k -b _fore200e_pca_fw \ + -i $(CONFIG_ATM_FORE200E_PCA_FW) -o $@ + +fore200e_sba_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_SBA_FW)) \ + fore200e_mkfirm + ./fore200e_mkfirm -k -b _fore200e_sba_fw \ + -i $(CONFIG_ATM_FORE200E_SBA_FW) -o $@ + +fore200e_mkfirm: fore200e_mkfirm.c + $(HOSTCC) $(HOSTCFLAGS) $< -o $@ + +# deal with the various suffixes of the firmware images +%.bin: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +%.bin1: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +%.bin2: %.data + objcopy -Iihex $< -Obinary $@.gz + gzip -df $@.gz + +# module build +fore_200e.o: fore200e.o $(FORE200E_FW_OBJS) + $(LD) -r -o $@ $< $(FORE200E_FW_OBJS) diff -u --recursive --new-file v2.3.47/linux/drivers/atm/atmdev_init.c linux/drivers/atm/atmdev_init.c --- v2.3.47/linux/drivers/atm/atmdev_init.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/atmdev_init.c Mon Feb 21 16:32:27 2000 @@ -28,6 +28,9 @@ #ifdef CONFIG_ATM_IA extern int ia_detect(void); #endif +#ifdef CONFIG_ATM_FORE200E +extern int fore200e_detect(void); +#endif int __init atmdev_init(void) @@ -55,6 +58,9 @@ #endif #ifdef CONFIG_ATM_IA devs += ia_detect(); +#endif +#ifdef CONFIG_ATM_FORE200E + devs += fore200e_detect(); #endif return devs; } diff -u --recursive --new-file v2.3.47/linux/drivers/atm/eni.c linux/drivers/atm/eni.c --- v2.3.47/linux/drivers/atm/eni.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/eni.c Mon Feb 21 16:32:27 2000 @@ -156,7 +156,8 @@ static struct atm_dev *eni_boards = NULL; -static u32 *zeroes = NULL; /* aligned "magic" zeroes */ +static u32 *cpu_zeroes = NULL; /* aligned "magic" zeroes */ +static dma_addr_t zeroes; /* Read/write registers on card */ #define eni_in(r) readl(eni_dev->reg+(r)*4) @@ -349,18 +350,21 @@ struct eni_vcc *eni_vcc; u32 dma_rd,dma_wr; u32 dma[RX_DMA_BUF*2]; - unsigned long paddr,here; + dma_addr_t paddr; + unsigned long here; int i,j; eni_dev = ENI_DEV(vcc->dev); eni_vcc = ENI_VCC(vcc); paddr = 0; /* GCC, shut up */ if (skb) { - paddr = (unsigned long) skb->data; + paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len, + PCI_DMA_FROMDEVICE); + ENI_PRV_PADDR(skb) = paddr; if (paddr & 3) printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d has " "mis-aligned RX data (0x%lx)\n",vcc->dev->number, - vcc->vci,paddr); + vcc->vci,(unsigned long) paddr); ENI_PRV_SIZE(skb) = size+skip; /* PDU plus descriptor */ ATM_SKB(skb)->vcc = vcc; @@ -390,7 +394,7 @@ if (init > words) init = words; dma[j++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += init << 2; words -= init; } @@ -399,7 +403,7 @@ dma[j++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~15) << 2; words &= 15; } @@ -409,7 +413,7 @@ dma[j++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~7) << 2; words &= 7; } @@ -419,7 +423,7 @@ dma[j++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~3) << 2; words &= 3; } @@ -429,7 +433,7 @@ dma[j++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; paddr += (words & ~1) << 2; words &= 1; } @@ -437,7 +441,7 @@ if (words) { dma[j++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = virt_to_bus((void *) paddr); + dma[j++] = paddr; } } if (size != eff) { @@ -447,8 +451,7 @@ } if (!j || j > 2*RX_DMA_BUF) { printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n"); - if (skb) kfree_skb(skb); - return -1; + goto trouble; } dma[j-2] |= MID_DMA_END; j = j >> 1; @@ -461,8 +464,7 @@ if (!NEPMOK(dma_wr,j+j+1,dma_rd,NR_DMA_RX)) { /* @@@ +1 is ugly */ printk(KERN_WARNING DEV_LABEL "(itf %d): RX DMA full\n", vcc->dev->number); - if (skb) kfree_skb(skb); - return -1; + goto trouble; } for (i = 0; i < j; i++) { writel(dma[i*2],eni_dev->rx_dma+dma_wr*8); @@ -472,12 +474,19 @@ if (skb) { ENI_PRV_POS(skb) = eni_vcc->descr+size+1; skb_queue_tail(&eni_dev->rx_queue,skb); -eni_vcc->last = skb; + eni_vcc->last = skb; rx_enqueued++; } eni_vcc->descr = here; eni_out(dma_wr,MID_DMA_WR_RX); return 0; + +trouble: + if (paddr) + pci_unmap_single(eni_dev->pci_dev,paddr,skb->len, + PCI_DMA_FROMDEVICE); + if (skb) dev_kfree_skb_irq(skb); + return -1; } @@ -747,7 +756,9 @@ } eni_vcc->rxing--; eni_vcc->rx_pos = ENI_PRV_POS(skb) & (eni_vcc->words-1); - if (!skb->len) kfree_skb(skb); + pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len, + PCI_DMA_TODEVICE); + if (!skb->len) dev_kfree_skb_irq(skb); else { EVENT("pushing (len=%ld)\n",skb->len,0); if (vcc->qos.aal == ATM_AAL0) @@ -902,13 +913,13 @@ enum enq_res { enq_ok,enq_next,enq_jam }; -static inline void put_dma(int chan,u32 *dma,int *j,unsigned long paddr, +static inline void put_dma(int chan,u32 *dma,int *j,dma_addr_t paddr, u32 size) { u32 init,words; - DPRINTK("put_dma: 0x%lx+0x%x\n",paddr,size); - EVENT("put_dma: 0x%lx+0x%lx\n",paddr,size); + DPRINTK("put_dma: 0x%lx+0x%x\n",(unsigned long) paddr,size); + EVENT("put_dma: 0x%lx+0x%lx\n",(unsigned long) paddr,size); #if 0 /* don't complain anymore */ if (paddr & 3) printk(KERN_ERR "put_dma: unaligned addr (0x%lx)\n",paddr); @@ -918,10 +929,11 @@ if (paddr & 3) { init = 4-(paddr & 3); if (init > size || size < 7) init = size; - DPRINTK("put_dma: %lx DMA: %d/%d bytes\n",paddr,init,size); + DPRINTK("put_dma: %lx DMA: %d/%d bytes\n", + (unsigned long) paddr,init,size); dma[(*j)++] = MID_DT_BYTE | (init << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += init; size -= init; } @@ -930,10 +942,11 @@ if (words && (paddr & 31)) { init = 8-((paddr & 31) >> 2); if (init > words) init = words; - DPRINTK("put_dma: %lx DMA: %d/%d words\n",paddr,init,words); + DPRINTK("put_dma: %lx DMA: %d/%d words\n", + (unsigned long) paddr,init,words); dma[(*j)++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += init << 2; words -= init; } @@ -943,18 +956,18 @@ words); dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~15) << 2; words &= 15; } #endif #ifdef CONFIG_ATM_ENI_BURST_TX_8W /* recommended */ if (words & ~7) { - DPRINTK("put_dma: %lx DMA: %d*8/%d words\n",paddr,words >> 3, - words); + DPRINTK("put_dma: %lx DMA: %d*8/%d words\n", + (unsigned long) paddr,words >> 3,words); dma[(*j)++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~7) << 2; words &= 7; } @@ -965,7 +978,7 @@ words); dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~3) << 2; words &= 3; } @@ -976,23 +989,25 @@ words); dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += (words & ~1) << 2; words &= 1; } #endif if (words) { - DPRINTK("put_dma: %lx DMA: %d words\n",paddr,words); + DPRINTK("put_dma: %lx DMA: %d words\n",(unsigned long) paddr, + words); dma[(*j)++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; paddr += words << 2; } if (size) { - DPRINTK("put_dma: %lx DMA: %d bytes\n",paddr,size); + DPRINTK("put_dma: %lx DMA: %d bytes\n",(unsigned long) paddr, + size); dma[(*j)++] = MID_DT_BYTE | (size << MID_DMA_COUNT_SHIFT) | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = virt_to_bus((void *) paddr); + dma[(*j)++] = paddr; } } @@ -1003,6 +1018,7 @@ struct eni_dev *eni_dev; struct eni_vcc *eni_vcc; struct eni_tx *tx; + dma_addr_t paddr; u32 dma_rd,dma_wr; u32 size; /* in words */ int aal5,dma_size,i,j; @@ -1079,6 +1095,9 @@ vcc->dev->number); return enq_jam; } + paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len, + PCI_DMA_TODEVICE); + ENI_PRV_PADDR(skb) = paddr; /* prepare DMA queue entries */ j = 0; eni_dev->dma[j++] = (((tx->tx_pos+TX_DESCR_SIZE) & (tx->words-1)) << @@ -1086,21 +1105,17 @@ MID_DT_JK; j++; if (!ATM_SKB(skb)->iovcnt) - if (aal5) - put_dma(tx->index,eni_dev->dma,&j, - (unsigned long) skb->data,skb->len); - else put_dma(tx->index,eni_dev->dma,&j, - (unsigned long) skb->data+4,skb->len-4); + if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len); + else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4); else { -DPRINTK("doing direct send\n"); +DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */ for (i = 0; i < ATM_SKB(skb)->iovcnt; i++) put_dma(tx->index,eni_dev->dma,&j,(unsigned long) ((struct iovec *) skb->data)[i].iov_base, ((struct iovec *) skb->data)[i].iov_len); } if (skb->len & 3) - put_dma(tx->index,eni_dev->dma,&j, - (unsigned long) zeroes,4-(skb->len & 3)); + put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3)); /* JK for AAL5 trailer - AAL0 doesn't need it, but who cares ... */ eni_dev->dma[j++] = (((tx->tx_pos+size) & (tx->words-1)) << MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) | @@ -1188,8 +1203,10 @@ break; } ENI_VCC(vcc)->txing -= ENI_PRV_SIZE(skb); + pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len, + PCI_DMA_TODEVICE); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_irq(skb); vcc->stats->tx++; wake_up(&eni_dev->tx_wait); dma_complete++; @@ -1670,7 +1687,7 @@ (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory " "(0x%02x)\n",dev->number,error); - return error; + return -EIO; } printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,", dev->number,revision,real_base,eni_dev->irq); @@ -2020,7 +2037,6 @@ if (!skb) { printk(KERN_CRIT "!skb in eni_send ?\n"); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); return -EINVAL; } if (vcc->qos.aal == ATM_AAL0) { @@ -2195,7 +2211,14 @@ struct atm_dev *dev; struct eni_dev *eni_dev; int devs,type; + struct sk_buff *skb; + DPRINTK("eni_detect\n"); + if (sizeof(skb->cb) < sizeof(struct eni_skb_prv)) { + printk(KERN_ERR "eni_detect: skb->cb is too small (%d < %d)\n", + sizeof(skb->cb),sizeof(struct eni_skb_prv)); + return 0; + } eni_dev = (struct eni_dev *) kmalloc(sizeof(struct eni_dev), GFP_KERNEL); if (!eni_dev) return -ENOMEM; @@ -2208,8 +2231,9 @@ PCI_DEVICE_ID_EF_ATM_ASIC : PCI_DEVICE_ID_EF_ATM_FPGA, pci_dev))) { if (!devs) { - zeroes = kmalloc(4,GFP_KERNEL); - if (!zeroes) { + cpu_zeroes = pci_alloc_consistent(pci_dev, + ENI_ZEROES_SIZE,&zeroes); + if (!cpu_zeroes) { kfree(eni_dev); return -ENOMEM; } @@ -2231,11 +2255,12 @@ if (!eni_dev) break; } } - kfree(eni_dev); - if (!devs && zeroes) { - kfree(zeroes); - zeroes = NULL; + if (!devs && cpu_zeroes) { + pci_free_consistent(eni_dev->pci_dev,ENI_ZEROES_SIZE, + cpu_zeroes,zeroes); + cpu_zeroes = NULL; } + kfree(eni_dev); return devs; } diff -u --recursive --new-file v2.3.47/linux/drivers/atm/eni.h linux/drivers/atm/eni.h --- v2.3.47/linux/drivers/atm/eni.h Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/eni.h Mon Feb 21 16:32:27 2000 @@ -27,6 +27,8 @@ #define DEFAULT_RX_MULT 300 /* max_sdu*3 */ #define DEFAULT_TX_MULT 300 /* max_sdu*3 */ +#define ENI_ZEROES_SIZE 4 /* need that many DMA-able zero bytes */ + struct eni_free { unsigned long start; /* counting in bytes */ @@ -113,9 +115,11 @@ struct atm_skb_data _; /* reserved */ unsigned long pos; /* position of next descriptor */ int size; /* PDU size in reassembly buffer */ + dma_addr_t paddr; /* DMA handle */ }; #define ENI_PRV_SIZE(skb) (((struct eni_skb_prv *) (skb)->cb)->size) #define ENI_PRV_POS(skb) (((struct eni_skb_prv *) (skb)->cb)->pos) +#define ENI_PRV_PADDR(skb) (((struct eni_skb_prv *) (skb)->cb)->paddr) #endif diff -u --recursive --new-file v2.3.47/linux/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c --- v2.3.47/linux/drivers/atm/fore200e.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/fore200e.c Mon Feb 21 16:32:27 2000 @@ -0,0 +1,2973 @@ +/* + $Id: fore200e.c,v 1.1 2000/02/21 16:04:31 davem Exp $ + + A FORE Systems 200E-series driver for ATM on Linux. + Christophe Lizzi (lizzi@cnam.fr), October 1999-February 2000. + + Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). + + This driver simultaneously supports PCA-200E and SBA-200E adapters + on i386, alpha (untested), powerpc, sparc and sparc64 architectures. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ATM_FORE200E_PCA +#include +#endif + +#ifdef CONFIG_ATM_FORE200E_SBA +#include +#include +#include +#include +#include +#endif + +#ifdef MODULE +#include +#endif + +#include "fore200e.h" +#include "suni.h" + +#if 1 /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */ +#define FORE200E_52BYTE_AAL0_SDU +#endif + +#define FORE200E_VERSION "0.2a" + + +#define FORE200E "fore200e: " + +#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) +#define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \ + printk(FORE200E format, ##args); } while(0) +#else +#define DPRINTK(level, format, args...) while(0) +#endif + + +#define FORE200E_ALIGN(addr, alignment) \ + ((((unsigned long)(addr) + (alignment - 1)) & ~(alignment - 1)) - (unsigned long)(addr)) + +#define FORE200E_DMA_INDEX(dma_addr, type, index) ((dma_addr) + (index) * sizeof(type)) + +#define FORE200E_INDEX(virt_addr, type, index) (&((type *)(virt_addr))[ index ]) + +#define FORE200E_NEXT_ENTRY(index, modulo) (index = ++(index) % (modulo)) + + +#define MSECS(ms) (((ms)*HZ/1000)+1) + + +extern const struct atmdev_ops fore200e_ops; +extern const struct fore200e_bus fore200e_bus[]; + +static struct fore200e* fore200e_boards = NULL; + + +#ifdef MODULE +MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen"); +MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION); +MODULE_SUPPORTED_DEVICE("PCA-200E, SBA-200E"); +#endif + + +static const int fore200e_rx_buf_nbr[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { + { BUFFER_S1_NBR, BUFFER_L1_NBR }, + { BUFFER_S2_NBR, BUFFER_L2_NBR } +}; + +static const int fore200e_rx_buf_size[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { + { BUFFER_S1_SIZE, BUFFER_L1_SIZE }, + { BUFFER_S2_SIZE, BUFFER_L2_SIZE } +}; + + +#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) +static const char* fore200e_traffic_class[] = { "NONE", "UBR", "CBR", "VBR", "ABR", "ANY" }; +#endif + + +#if 0 /* currently unused */ +static int +fore200e_fore2atm_aal(enum fore200e_aal aal) +{ + switch(aal) { + case FORE200E_AAL0: return ATM_AAL0; + case FORE200E_AAL34: return ATM_AAL34; + case FORE200E_AAL5: return ATM_AAL5; + } + + return -EINVAL; +} +#endif + + +static enum fore200e_aal +fore200e_atm2fore_aal(int aal) +{ + switch(aal) { + case ATM_AAL0: return FORE200E_AAL0; + case ATM_AAL34: return FORE200E_AAL34; + case ATM_AAL1: + case ATM_AAL2: + case ATM_AAL5: return FORE200E_AAL5; + } + + return -EINVAL; +} + + +static char* +fore200e_irq_itoa(int irq) +{ +#if defined(__sparc_v9__) + return __irq_itoa(irq); +#else + static char str[8]; + sprintf(str, "%d", irq); + return str; +#endif +} + + +static void* +fore200e_kmalloc(int size, int flags) +{ + void* chunk = kmalloc(size, flags); + + if (chunk) + memset(chunk, 0x00, size); + else + printk(FORE200E "kmalloc() failed, requested size = %d, flags = 0x%x\n", size, flags); + + return chunk; +} + + +static void +fore200e_kfree(void* chunk) +{ + kfree(chunk); +} + + +/* allocate and align a chunk of memory intended to hold the data behing exchanged + between the driver and the adapter (using streaming DVMA on SBUS hosts) */ + +static int +fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment) +{ + unsigned long offset = 0; + + if (alignment <= sizeof(int)) + alignment = 0; + + chunk->alloc_size = size + alignment; + chunk->align_size = size; + + chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA); + if (chunk->alloc_addr == NULL) + return -ENOMEM; + + if (alignment > 0) + offset = FORE200E_ALIGN(chunk->alloc_addr, alignment); + + chunk->align_addr = chunk->alloc_addr + offset; + + chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size); + + return 0; +} + + +/* free a chunk of memory */ + +static void +fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ + fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size); + + fore200e_kfree(chunk->alloc_addr); +} + + + +#if 0 /* currently unused */ +static int +fore200e_checkup(struct fore200e* fore200e) +{ + u32 hb1, hb2; + + hb1 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + fore200e_spin(10); + hb2 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + + if (hb2 <= hb1) { + printk(FORE200E "device %s heartbeat is not counting upwards, hb1 = %x; hb2 = %x\n", + fore200e->name, hb1, hb2); + return -EIO; + } + printk(FORE200E "device %s heartbeat is ok\n", fore200e->name); + + return 0; +} +#endif + + +static void +fore200e_spin(int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + while (jiffies < timeout); +} + + +static int +fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + int ok; + + mb(); + do { + if ((ok = (*addr == val)) || (*addr & STATUS_ERROR)) + break; + + } while (jiffies < timeout); + +#if 1 + if (!ok) { + printk(FORE200E "cmd polling failed, got status 0x%08x, expected 0x%08x\n", + *addr, val); + } +#endif + + return ok; +} + + +static int +fore200e_io_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs) +{ + unsigned long timeout = jiffies + MSECS(msecs); + int ok; + + do { + if ((ok = (fore200e->bus->read(addr) == val))) + break; + + } while (jiffies < timeout); + +#if 1 + if (!ok) { + printk(FORE200E "I/O polling failed, got status 0x%08x, expected 0x%08x\n", + fore200e->bus->read(addr), val); + } +#endif + + return ok; +} + + +static void +fore200e_free_rx_buf(struct fore200e* fore200e) +{ + int scheme, magn, nbr; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + if ((buffer = fore200e->host_bsq[ scheme ][ magn ].buffer) != NULL) { + + for (nbr = 0; nbr < fore200e_rx_buf_nbr[ scheme ][ magn ]; nbr++) { + + struct chunk* data = &buffer[ nbr ].data; + + if (data->alloc_addr != NULL) + fore200e_chunk_free(fore200e, data); + } + } + } + } +} + + +static void +fore200e_uninit_bs_queue(struct fore200e* fore200e) +{ + int scheme, magn; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + struct chunk* status = &fore200e->host_bsq[ scheme ][ magn ].status; + struct chunk* rbd_block = &fore200e->host_bsq[ scheme ][ magn ].rbd_block; + + if (status->alloc_addr) + fore200e->bus->dma_chunk_free(fore200e, status); + + if (rbd_block->alloc_addr) + fore200e->bus->dma_chunk_free(fore200e, rbd_block); + } + } +} + + +static int +fore200e_reset(struct fore200e* fore200e, int diag) +{ + int ok; + + fore200e->cp_monitor = (struct cp_monitor*)(fore200e->virt_base + FORE200E_CP_MONITOR_OFFSET); + + fore200e->bus->write(BSTAT_COLD_START, &fore200e->cp_monitor->bstat); + + fore200e->bus->reset(fore200e); + + if (diag) { + ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_SELFTEST_OK, 1000); + if (ok == 0) { + + printk(FORE200E "device %s self-test failed\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s self-test passed\n", fore200e->name); + + fore200e->state = FORE200E_STATE_RESET; + } + + return 0; +} + + +static void +fore200e_shutdown(struct fore200e* fore200e) +{ + printk(FORE200E "removing device %s at 0x%lx, IRQ %s\n", + fore200e->name, fore200e->phys_base, + fore200e_irq_itoa(fore200e->irq)); + + if (fore200e->state > FORE200E_STATE_RESET) { + /* first, reset the board to prevent further interrupts or data transfers */ + fore200e_reset(fore200e, 0); + } + + /* then, release all allocated resources */ + switch(fore200e->state) { + + case FORE200E_STATE_COMPLETE: + if (fore200e->stats) + kfree(fore200e->stats); + + case FORE200E_STATE_IRQ: + free_irq(fore200e->irq, fore200e->atm_dev); + + case FORE200E_STATE_ALLOC_BUF: + fore200e_free_rx_buf(fore200e); + + case FORE200E_STATE_INIT_BSQ: + fore200e_uninit_bs_queue(fore200e); + + case FORE200E_STATE_INIT_RXQ: + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.status); + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.rpd); + + case FORE200E_STATE_INIT_TXQ: + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.status); + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.tpd); + + case FORE200E_STATE_INIT_CMDQ: + fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_cmdq.status); + + case FORE200E_STATE_INITIALIZE: + /* nothing to do for that state */ + + case FORE200E_STATE_START_FW: + /* nothing to do for that state */ + + case FORE200E_STATE_LOAD_FW: + /* nothing to do for that state */ + + case FORE200E_STATE_RESET: + /* nothing to do for that state */ + + case FORE200E_STATE_MAP: + fore200e->bus->unmap(fore200e); + + case FORE200E_STATE_CONFIGURE: + /* nothing to do for that state */ + + case FORE200E_STATE_REGISTER: + /* XXX shouldn't we *start* by deregistering the device? */ + atm_dev_deregister(fore200e->atm_dev); + + case FORE200E_STATE_BLANK: + /* nothing to do for that state */ + } +} + + +#ifdef CONFIG_ATM_FORE200E_PCA + +static u32 fore200e_pca_read(volatile u32* addr) +{ + /* on big-endian hosts, the board is configured to convert + the endianess of slave RAM accesses */ + return le32_to_cpu(readl(addr)); +} + + +static void fore200e_pca_write(u32 val, volatile u32* addr) +{ + /* on big-endian hosts, the board is configured to convert + the endianess of slave RAM accesses */ + writel(cpu_to_le32(val), addr); +} + + +static u32 +fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size) +{ + u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, PCI_DMA_BIDIRECTIONAL); + + DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", + virt_addr, size, dma_addr); + + return dma_addr; +} + + +static void +fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, + PCI_DMA_BIDIRECTIONAL); +} + + +static void +fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, + PCI_DMA_BIDIRECTIONAL); +} + + +/* allocate a DMA consistent chunk of memory intended to act as a communication mechanism + (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ + +static int +fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) +{ +#if defined(__sparc_v9__) + /* returned chunks are page-aligned */ + chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev, + chunk->alloc_size, + &chunk->dma_addr); + + if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) + return -ENOMEM; + + chunk->align_addr = chunk->alloc_addr; +#else + if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment) < 0) + return -ENOMEM; + + chunk->dma_addr = fore200e_pca_dma_map(fore200e, chunk->align_addr, chunk->align_size); +#endif + + return 0; +} + + +/* free a DMA consistent chunk of memory */ + +static void +fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ +#if defined(__sparc_v9__) + pci_free_consistent((struct pci_dev*)fore200e->bus_dev, + chunk->alloc_size, + chunk->alloc_addr, + chunk->dma_addr); +#else + fore200e_pca_dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size); + + fore200e_chunk_free(fore200e, chunk); +#endif +} + + +static int +fore200e_pca_irq_check(struct fore200e* fore200e) +{ + /* this is a 1 bit register */ + return readl(fore200e->regs.pca.psr); +} + + +static void +fore200e_pca_irq_ack(struct fore200e* fore200e) +{ + writel(PCA200E_HCR_CLRINTR, fore200e->regs.pca.hcr); +} + + +static void +fore200e_pca_reset(struct fore200e* fore200e) +{ + writel(PCA200E_HCR_RESET, fore200e->regs.pca.hcr); + fore200e_spin(10); + writel(0, fore200e->regs.pca.hcr); +} + + +static int __init +fore200e_pca_map(struct fore200e* fore200e) +{ + DPRINTK(2, "device %s being mapped in memory\n", fore200e->name); + + fore200e->virt_base = ioremap(fore200e->phys_base, PCA200E_IOSPACE_LENGTH); + + if (fore200e->virt_base == NULL) { + printk(FORE200E "can't map device %s\n", fore200e->name); + return -EFAULT; + } + + DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); + + /* gain access to the PCA-200E specific registers */ + fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET); + fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET); + fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET); + + fore200e->state = FORE200E_STATE_MAP; + return 0; +} + + +static void +fore200e_pca_unmap(struct fore200e* fore200e) +{ + DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name); + + /* XXX iounmap() does nothing on PowerPC (at least in 2.2.12 and 2.3.41), + this leads to a kernel panic if the module is loaded and unloaded several times */ + if (fore200e->virt_base != NULL) + iounmap(fore200e->virt_base); +} + + +static int __init +fore200e_pca_configure(struct fore200e* fore200e) +{ + struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; + u8 master_ctrl; + + DPRINTK(2, "device %s being configured\n", fore200e->name); + + if ((pci_dev->irq == 0) || (pci_dev->irq == 0xFF)) { + printk(FORE200E "incorrect IRQ setting - misconfigured PCI-PCI bridge?\n"); + return -EIO; + } + + pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl); + + master_ctrl = master_ctrl +#if 0 + | PCA200E_CTRL_DIS_CACHE_RD + | PCA200E_CTRL_DIS_WRT_INVAL +#endif +#if defined(__BIG_ENDIAN) + /* request the PCA board to convert the endianess of slave RAM accesses */ + | PCA200E_CTRL_CONVERT_ENDIAN +#endif + | PCA200E_CTRL_LARGE_PCI_BURSTS; + + pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl); + + fore200e->state = FORE200E_STATE_CONFIGURE; + return 0; +} + + +static struct fore200e* __init +fore200e_pca_detect(const struct fore200e_bus* bus, int index) +{ + struct fore200e* fore200e; + struct pci_dev* pci_dev = NULL; + int count = index; + + if (pci_present() == 0) { + printk(FORE200E "no PCI subsystem\n"); + return NULL; + } + + do { + pci_dev = pci_find_device(PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, pci_dev); + if (pci_dev == NULL) + return NULL; + } while (count--); + + fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); + if (fore200e == NULL) + return NULL; + + fore200e->bus = bus; + fore200e->bus_dev = pci_dev; + fore200e->irq = pci_dev->irq; + fore200e->phys_base = (pci_dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK); + +#if defined(__powerpc__) + fore200e->phys_base += KERNELBASE; +#endif + + sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + + pci_set_master(pci_dev); + + return fore200e; +} + + +static int __init +fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct prom_opcode opcode; + int ok; + u32 prom_dma; + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_PROM; + opcode.pad = 0; + + prom_dma = fore200e->bus->dma_map(fore200e, prom, sizeof(struct prom_data)); + + fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.prom_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + fore200e->bus->dma_unmap(fore200e, prom_dma, sizeof(struct prom_data)); + + if (ok == 0) { + printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name); + return -EIO; + } + +#if defined(__BIG_ENDIAN) + +#define swap_here(addr) (*((u32*)(addr)) = swab32( *((u32*)(addr)) )) + + /* MAC address is stored as little-endian */ + swap_here(&prom->mac_addr[0]); + swap_here(&prom->mac_addr[4]); +#endif + + return 0; +} + + +static int +fore200e_pca_proc_read(struct fore200e* fore200e, char *page) +{ + struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; + + return sprintf(page, " PCI bus/slot/function:\t%d/%d/%d\n", + pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); +} + +#endif /* CONFIG_ATM_FORE200E_PCA */ + + + + +#ifdef CONFIG_ATM_FORE200E_SBA + +static u32 +fore200e_sba_read(volatile u32* addr) +{ + return sbus_readl(addr); +} + + +static void +fore200e_sba_write(u32 val, volatile u32* addr) +{ + sbus_writel(val, addr); +} + + +static u32 +fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size) +{ + u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size); + + DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d --> dma_addr = 0x%08x\n", virt_addr, size, dma_addr); + + return dma_addr; +} + + +static void +fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size); +} + + +static void +fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size) +{ + DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d\n", dma_addr, size); + + sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size); +} + + +/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism + (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */ + +static int +fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int nbr, int alignment) +{ + chunk->alloc_size = chunk->align_size = size * nbr; + + /* returned chunks are page-aligned */ + chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev, + chunk->alloc_size, + &chunk->dma_addr); + + if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) + return -ENOMEM; + + chunk->align_addr = chunk->alloc_addr; + + return 0; +} + + +/* free a DVMA consistent chunk of memory */ + +static void +fore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) +{ + sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev, + chunk->alloc_size, + chunk->alloc_addr, + chunk->dma_addr); +} + + +static void +fore200e_sba_irq_enable(struct fore200e* fore200e) +{ + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr); +} + + +static int +fore200e_sba_irq_check(struct fore200e* fore200e) +{ + return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ; +} + + +static void +fore200e_sba_irq_ack(struct fore200e* fore200e) +{ + u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; + fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr); +} + + +static void +fore200e_sba_reset(struct fore200e* fore200e) +{ + fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr); + fore200e_spin(10); + fore200e->bus->write(0, fore200e->regs.sba.hcr); +} + + +static int __init +fore200e_sba_map(struct fore200e* fore200e) +{ + struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; + unsigned int bursts; + + /* gain access to the SBA-200E specific registers */ + + fore200e->regs.sba.hcr = (u32*)sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); + fore200e->regs.sba.bsr = (u32*)sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); + fore200e->regs.sba.isr = (u32*)sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); + fore200e->virt_base = (u32*)sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM"); + + if (fore200e->virt_base == NULL) { + printk(FORE200E "unable to map RAM of device %s\n", fore200e->name); + return -EFAULT; + } + + DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); + + fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */ + + /* get the supported DVMA burst sizes */ + bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00); + + if (sbus_can_dma_64bit(sbus_dev)) + sbus_set_sbus64(sbus_dev, bursts); + +#if 0 + if (bursts & DMA_BURST16) + fore200e->bus->write(SBA200E_BSR_BURST16, fore200e->regs.sba.bsr); + else + if (bursts & DMA_BURST8) + fore200e->bus->write(SBA200E_BSR_BURST8, fore200e->regs.sba.bsr); + else + if (bursts & DMA_BURST4) + fore200e->bus->write(SBA200E_BSR_BURST4, fore200e->regs.sba.bsr); +#endif + + fore200e->state = FORE200E_STATE_MAP; + return 0; +} + + +static void +fore200e_sba_unmap(struct fore200e* fore200e) +{ + sbus_iounmap((ulong)fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH); + sbus_iounmap((ulong)fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH); + sbus_iounmap((ulong)fore200e->regs.sba.isr, SBA200E_ISR_LENGTH); + sbus_iounmap((ulong)fore200e->virt_base, SBA200E_RAM_LENGTH); +} + + +static int __init +fore200e_sba_configure(struct fore200e* fore200e) +{ + fore200e->state = FORE200E_STATE_CONFIGURE; + return 0; +} + + +static struct fore200e* __init +fore200e_sba_detect(const struct fore200e_bus* bus, int index) +{ + struct fore200e* fore200e; + struct sbus_bus* sbus_bus; + struct sbus_dev* sbus_dev = NULL; + + unsigned int count = 0; + + for_each_sbus (sbus_bus) { + for_each_sbusdev (sbus_dev, sbus_bus) { + if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) { + if (count >= index) + goto found; + count++; + } + } + } + return NULL; + + found: +#if 1 + if (sbus_dev->num_registers != 4) { + printk(FORE200E "this %s device has %d instead of 4 registers\n", + bus->model_name, sbus_dev->num_registers); + return NULL; + } +#endif + + fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); + if (fore200e == NULL) + return NULL; + + fore200e->bus = bus; + fore200e->bus_dev = sbus_dev; + fore200e->irq = sbus_dev->irqs[ 0 ]; + + fore200e->phys_base = (unsigned long)sbus_dev; + + sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); + + return fore200e; +} + + +static int __init +fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom) +{ + struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev; + int len; + + len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4); + if (len < 0) + return -EBUSY; + + len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4); + if (len < 0) + return -EBUSY; + + prom_getproperty(sbus_dev->prom_node, "serialnumber", + (char*)&prom->serial_number, sizeof(prom->serial_number)); + + prom_getproperty(sbus_dev->prom_node, "promversion", + (char*)&prom->hw_revision, sizeof(prom->hw_revision)); + + return 0; +} + + +static int +fore200e_sba_proc_read(struct fore200e* fore200e, char *page) +{ + struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; + + return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name); +} +#endif /* CONFIG_ATM_FORE200E_SBA */ + + +static void +fore200e_irq_tx(struct fore200e* fore200e) +{ + struct host_txq_entry* entry; + int i; + + entry = fore200e->host_txq.host_entry; + + for (i = 0; i < QUEUE_SIZE_TX; i++) { + + if (*entry->status & STATUS_COMPLETE) { + + DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb); + + /* free copy of misaligned data */ + if (entry->data) + kfree(entry->data); + + /* remove DMA mapping */ + fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length); + + /* notify tx completion */ + if (entry->vcc->pop) + entry->vcc->pop(entry->vcc, entry->skb); + else + dev_kfree_skb_irq(entry->skb); + + /* check error condition */ + if (*entry->status & STATUS_ERROR) + entry->vcc->stats->tx_err++; + else + entry->vcc->stats->tx++; + + *entry->status = STATUS_FREE; + + fore200e->host_txq.txing--; + } + entry++; + } +} + + +static void +fore200e_supply(struct fore200e* fore200e) +{ + int scheme, magn, i; + + struct host_bsq* bsq; + struct host_bsq_entry* entry; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) { + + DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n", + scheme, magn, bsq->count); + + entry = &bsq->host_entry[ bsq->head ]; + + FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS); + + for (i = 0; i < RBD_BLK_SIZE; i++) { + + buffer = &bsq->buffer[ bsq->free ]; + + FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]); + + entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr; + entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer); + } + + /* increase the number of supplied rx buffers */ + bsq->count += RBD_BLK_SIZE; + + *entry->status = STATUS_PENDING; + fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr); + } + } + } +} + + + +static struct atm_vcc* +fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd) +{ + struct atm_vcc* vcc; + + for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { + + if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) + break; + } + + return vcc; +} + + +static void +fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd) +{ + struct atm_vcc* vcc; + struct sk_buff* skb; + struct buffer* buffer; + struct fore200e_vcc* fore200e_vcc; + int i, pdu_len = 0; +#ifdef FORE200E_52BYTE_AAL0_SDU + u32 cell_header = 0; +#endif + + vcc = fore200e_find_vcc(fore200e, rpd); + if (vcc == NULL) { + + printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n", + fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci); + return; + } + + fore200e_vcc = FORE200E_VCC(vcc); + +#ifdef FORE200E_52BYTE_AAL0_SDU + if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) { + + cell_header = (rpd->atm_header.gfc << ATM_HDR_GFC_SHIFT) | + (rpd->atm_header.vpi << ATM_HDR_VPI_SHIFT) | + (rpd->atm_header.vci << ATM_HDR_VCI_SHIFT) | + (rpd->atm_header.plt << ATM_HDR_PTI_SHIFT) | + rpd->atm_header.clp; + pdu_len = 4; + } +#endif + + /* compute total PDU length */ + for (i = 0; i < rpd->nseg; i++) + pdu_len += rpd->rsd[ i ].length; + + skb = alloc_skb(pdu_len, GFP_ATOMIC); + if (skb == NULL) { + + printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len); + vcc->stats->rx_drop++; + return; + } + + skb->stamp = vcc->timestamp = xtime; + +#ifdef FORE200E_52BYTE_AAL0_SDU + if (cell_header) { + *((u32*)skb_put(skb, 4)) = cell_header; + } +#endif + + /* reassemble segments */ + for (i = 0; i < rpd->nseg; i++) { + + /* rebuild rx buffer address from rsd handle */ + buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); + + /* ensure DMA synchronisation */ + fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length); + + memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length); + } + + DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize); + + if (pdu_len < fore200e_vcc->rx_min_pdu) + fore200e_vcc->rx_min_pdu = pdu_len; + if (pdu_len > fore200e_vcc->rx_max_pdu) + fore200e_vcc->rx_max_pdu = pdu_len; + + /* push PDU */ + if (atm_charge(vcc, skb->truesize) == 0) { + + DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n", + vcc->itf, vcc->vpi, vcc->vci); + + dev_kfree_skb_irq(skb); + return; + } + + vcc->push(vcc, skb); + vcc->stats->rx++; +} + + +static void +fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd) +{ + struct buffer* buffer; + int i; + + for (i = 0; i < rpd->nseg; i++) { + + /* rebuild rx buffer address from rsd handle */ + buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); + + /* decrease the number of supplied rx buffers */ + fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--; + } +} + + +static void +fore200e_irq_rx(struct fore200e* fore200e) +{ + struct host_rxq* rxq = &fore200e->host_rxq; + struct host_rxq_entry* entry; + + for (;;) { + + entry = &rxq->host_entry[ rxq->head ]; + + /* no more received PDUs */ + if ((*entry->status & STATUS_COMPLETE) == 0) + break; + + FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); + + if ((*entry->status & STATUS_ERROR) == 0) { + + fore200e_push_rpd(fore200e, entry->rpd); + } + else { + printk(FORE200E "damaged PDU on %d.%d.%d\n", + fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); + } + + fore200e_collect_rpd(fore200e, entry->rpd); + + fore200e_supply(fore200e); + + /* rewrite the rpd address to ack the received PDU */ + fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr); + *entry->status = STATUS_FREE; + } +} + + +static void +fore200e_interrupt(int irq, void* dev, struct pt_regs* regs) +{ + struct fore200e* fore200e = FORE200E_DEV((struct atm_dev*)dev); + + if (fore200e->bus->irq_check(fore200e) == 0) { + + DPRINTK(3, "unexpected interrupt on device %c\n", fore200e->name[9]); + return; + } + DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]); + + fore200e_irq_rx(fore200e); + + if (fore200e->host_txq.txing) + fore200e_irq_tx(fore200e); + + fore200e->bus->irq_ack(fore200e); +} + + +static int +fore200e_select_scheme(struct atm_vcc* vcc) +{ + int scheme; + +#if 1 + /* fairly balance VCs over (identical) buffer schemes */ + scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO; +#else + /* bit 7 of VPI magically selects the second buffer scheme */ + if (vcc->vpi & (1<<7)) { + vcc->vpi &= ((1<<7) - 1); /* reset the magic bit */ + scheme = BUFFER_SCHEME_TWO; + } + else { + scheme = BUFFER_SCHEME_ONE; + } +#endif + + DPRINTK(1, "vpvc %d.%d.%d uses the %s buffer scheme\n", + vcc->itf, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second"); + + return scheme; +} + + + +static int +fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct activate_opcode activ_opcode; + struct deactivate_opcode deactiv_opcode; + struct vpvc vpvc; + int ok; + enum fore200e_aal aal = fore200e_atm2fore_aal(vcc->qos.aal); + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + if (activate) { + FORE200E_VCC(vcc)->scheme = fore200e_select_scheme(vcc); + + activ_opcode.opcode = OPCODE_ACTIVATE_VCIN; + activ_opcode.aal = aal; + activ_opcode.scheme = FORE200E_VCC(vcc)->scheme; + activ_opcode.pad = 0; + } + else { + deactiv_opcode.opcode = OPCODE_DEACTIVATE_VCIN; + deactiv_opcode.pad = 0; + } + + vpvc.vci = vcc->vci; + vpvc.vpi = vcc->vpi; + + *entry->status = STATUS_PENDING; + + if (activate) { + +#ifdef FORE200E_52BYTE_AAL0_SDU + mtu = 48; +#endif + /* the MTU is unused by the cp, except in the case of AAL0 */ + fore200e->bus->write(mtu, &entry->cp_entry->cmd.activate_block.mtu); + fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.activate_block.vpvc); + fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode); + } + else { + fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.deactivate_block.vpvc); + fore200e->bus->write(*(u32*)&deactiv_opcode, (u32*)&entry->cp_entry->cmd.deactivate_block.opcode); + } + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to %s vpvc %d.%d on device %s\n", + activate ? "open" : "close", vcc->vpi, vcc->vci, fore200e->name); + return -EIO; + } + + DPRINTK(1, "vpvc %d.%d %sed on device %s\n", vcc->vpi, vcc->vci, + activate ? "open" : "clos", fore200e->name); + + return 0; +} + + +static int +fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci) +{ + struct atm_vcc* walk; + + /* find a free VPI */ + if (*vpi == ATM_VPI_ANY) { + + for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) { + + if ((walk->vci == *vci) && (walk->vpi == *vpi)) { + (*vpi)++; + walk = vcc->dev->vccs; + } + } + } + + /* find a free VCI */ + if (*vci == ATM_VCI_ANY) { + + for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) { + + if ((walk->vpi = *vpi) && (walk->vci == *vci)) { + *vci = walk->vci + 1; + walk = vcc->dev->vccs; + } + } + } + + return 0; +} + + +#define FORE200E_MAX_BACK2BACK_CELLS 255 /* XXX depends on CDVT */ + +static void +fore200e_rate_ctrl(struct atm_qos* qos, struct tpd_rate* rate) +{ + if (qos->txtp.max_pcr < ATM_OC3_PCR) { + + /* compute the data cells to idle cells ratio from the PCR */ + rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR; + rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells; + } + else { + /* disable rate control */ + rate->data_cells = rate->idle_cells = 0; + } +} + + +static int +fore200e_open(struct atm_vcc *vcc, short vpi, int vci) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc; + + /* find a free VPI/VCI */ + fore200e_walk_vccs(vcc, &vpi, &vci); + + vcc->vpi = vpi; + vcc->vci = vci; + + /* ressource checking only? */ + if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) + return 0; + + vcc->flags |= ATM_VF_ADDR; + vcc->itf = vcc->dev->number; + + DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " + "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + fore200e_traffic_class[ vcc->qos.txtp.traffic_class ], + vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_cdv, vcc->qos.txtp.max_sdu, + fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ], + vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu); + + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + + down(&fore200e->rate_sf); + if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { + up(&fore200e->rate_sf); + return -EAGAIN; + } + /* reserving the pseudo-CBR bandwidth at this point grants us + to reduce the length of the critical section protected + by 'rate_sf'. in counterpart, we have to reset the available + bandwidth if we later encounter an error */ + + fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + } + + fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_KERNEL); + if (fore200e_vcc == NULL) { + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + return -ENOMEM; + } + + FORE200E_VCC(vcc) = fore200e_vcc; + + if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) { + kfree(fore200e_vcc); + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + return -EBUSY; + } + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + /* compute rate control parameters */ + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + + fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate); + + DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + vcc->qos.txtp.max_pcr, vcc->qos.rxtp.max_pcr, + fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells); + } + + fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536; + fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; + + vcc->flags |= ATM_VF_READY; + return 0; +} + + + +static void +fore200e_close(struct atm_vcc* vcc) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal)); + + fore200e_activate_vcin(fore200e, 0, vcc, 0); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + + kfree(FORE200E_VCC(vcc)); + + if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { + down(&fore200e->rate_sf); + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + up(&fore200e->rate_sf); + } +} + + +#if 0 +#define FORE200E_SYNC_SEND /* wait tx completion before returning */ +#endif + + +static int +fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); + struct host_txq* txq = &fore200e->host_txq; + struct host_txq_entry* entry; + struct tpd* tpd; + struct tpd_haddr tpd_haddr; + unsigned long flags; + int retry = CONFIG_ATM_FORE200E_TX_RETRY; + int tx_copy = 0; + int tx_len = skb->len; + u32* cell_header = NULL; + unsigned char* skb_data; + int skb_len; + +#ifdef FORE200E_52BYTE_AAL0_SDU + if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) { + cell_header = (u32*) skb->data; + skb_data = skb->data + 4; /* skip 4-byte cell header */ + skb_len = tx_len = skb->len - 4; + + DPRINTK(3, "skipping user-supplied cell header 0x%08x", *cell_header); + } + else +#endif + { + skb_data = skb->data; + skb_len = skb->len; + } + + retry_here: + + spin_lock_irqsave(&fore200e->tx_lock, flags); + + entry = &txq->host_entry[ txq->head ]; + + if (*entry->status != STATUS_FREE) { + + /* try to free completed tx queue entries */ + fore200e_irq_tx(fore200e); + + if (*entry->status != STATUS_FREE) { + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + + /* retry once again? */ + if(--retry > 0) + goto retry_here; + + vcc->stats->tx_err++; + + printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", + fore200e->name, fore200e->cp_queues->heartbeat); + + return -EIO; + } + } + + tpd = entry->tpd; + + if (((unsigned long)skb_data) & 0x3) { + + DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name); + tx_copy = 1; + tx_len = skb_len; + } + + if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) { + + /* this simply NUKES the PCA-200E board */ + DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name); + tx_copy = 1; + tx_len = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD; + } + + if (tx_copy) { + + entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); + if (entry->data == NULL) { + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + return -ENOMEM; + } + + memcpy(entry->data, skb_data, skb_len); + if (skb_len < tx_len) + memset(entry->data + skb_len, 0x00, tx_len - skb_len); + + tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len); + } + else { + entry->data = NULL; + tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len); + } + + tpd->tsd[ 0 ].length = tx_len; + + FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); + txq->txing++; + + spin_unlock_irqrestore(&fore200e->tx_lock, flags); + + /* ensure DMA synchronisation */ + fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length); + + DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", + vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + tpd->tsd[0].length, skb_len); + + if (skb_len < fore200e_vcc->tx_min_pdu) + fore200e_vcc->tx_min_pdu = skb_len; + if (skb_len > fore200e_vcc->tx_max_pdu) + fore200e_vcc->tx_max_pdu = skb_len; + + entry->vcc = vcc; + entry->skb = skb; + + /* set tx rate control information */ + tpd->rate.data_cells = fore200e_vcc->rate.data_cells; + tpd->rate.idle_cells = fore200e_vcc->rate.idle_cells; + + if (cell_header) { + tpd->atm_header.clp = (*cell_header & ATM_HDR_CLP); + tpd->atm_header.plt = (*cell_header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; + tpd->atm_header.vci = (*cell_header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; + tpd->atm_header.vpi = (*cell_header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; + tpd->atm_header.gfc = (*cell_header & ATM_HDR_GFC_MASK) >> ATM_HDR_GFC_SHIFT; + } + else { + /* set the ATM header, common to all cells conveying the PDU */ + tpd->atm_header.clp = 0; + tpd->atm_header.plt = 0; + tpd->atm_header.vci = vcc->vci; + tpd->atm_header.vpi = vcc->vpi; + tpd->atm_header.gfc = 0; + } + + tpd->spec.length = tx_len; + tpd->spec.nseg = 1; + tpd->spec.aal = fore200e_atm2fore_aal(vcc->qos.aal); +#ifdef FORE200E_SYNC_SEND + tpd->spec.intr = 0; +#else + tpd->spec.intr = 1; +#endif + + tpd_haddr.size = sizeof(struct tpd) / 32; /* size is expressed in 32 byte blocks */ + tpd_haddr.pad = 0; + tpd_haddr.haddr = entry->tpd_dma >> 5; /* shift the address, as we are in a bitfield */ + + *entry->status = STATUS_PENDING; + fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr); + + +#ifdef FORE200E_SYNC_SEND + { + int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10); + + fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length); + + if (ok == 0) { + printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci); + + entry->vcc->stats->tx_err++; + return -EIO; + } + entry->vcc->stats->tx++; + + DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci); + + /* free tmp copy of misaligned data */ + if (entry->data) + kfree(entry->data); + + /* notify tx completion */ + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb(skb); + } +#endif + + return 0; +} + + +static int +fore200e_getstats(struct fore200e* fore200e) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct stats_opcode opcode; + int ok; + u32 stats_dma_addr; + + if (fore200e->stats == NULL) { + fore200e->stats = fore200e_kmalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA); + if (fore200e->stats == NULL) + return -ENOMEM; + } + + stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats)); + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_STATS; + opcode.pad = 0; + + fore200e->bus->write(stats_dma_addr, &entry->cp_entry->cmd.stats_block.stats_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.stats_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats)); + + if (ok == 0) { + printk(FORE200E "unable to get statistics from device %s\n", fore200e->name); + return -EIO; + } + + return 0; +} + + +static int +fore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) +{ + // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", + vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); + + return -EINVAL; +} + + +static int +fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) +{ + // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", + vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); + + return -EINVAL; +} + + +#if 0 /* currently unused */ +static int +fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct oc3_opcode opcode; + int ok; + u32 oc3_regs_dma_addr; + + oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs)); + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_GET_OC3; + opcode.reg = 0; + opcode.value = 0; + opcode.mask = 0; + + fore200e->bus->write(oc3_regs_dma_addr, &entry->cp_entry->cmd.oc3_block.regs_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + fore200e->bus_dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs)); + + if (ok == 0) { + printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name); + return -EIO; + } + + return 0; +} +#endif + + +static int +fore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; + struct oc3_opcode opcode; + int ok; + + FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); + + opcode.opcode = OPCODE_SET_OC3; + opcode.reg = reg; + opcode.value = value; + opcode.mask = mask; + + fore200e->bus->write(0, &entry->cp_entry->cmd.oc3_block.regs_haddr); + + *entry->status = STATUS_PENDING; + + fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); + + ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); + + *entry->status = STATUS_FREE; + + if (ok == 0) { + printk(FORE200E "unable to set OC-3 reg 0x%02x of device %s\n", reg, fore200e->name); + return -EIO; + } + + return 0; +} + + +static int +fore200e_setloop(struct fore200e* fore200e, int loop_mode) +{ + u32 mct_value, mct_mask; + int error; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + switch (loop_mode) { + + case SUNI_LM_NONE: + mct_value = 0; + mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE; + break; + + case SUNI_LM_DIAG: + mct_value = mct_mask = SUNI_MCT_DLE; + break; + + case SUNI_LM_LOOP: + mct_value = mct_mask = SUNI_MCT_LLE; + break; + + default: + return -EINVAL; + } + + error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask); + if ( error == 0) + fore200e->loop_mode = loop_mode; + + return error; +} + + +static inline unsigned int +fore200e_swap(unsigned int in) +{ +#if defined(__LITTLE_ENDIAN) + return swab32(in); +#else + return in; +#endif +} + + +static int +fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats* arg) +{ + struct sonet_stats tmp; + + if (fore200e_getstats(fore200e) < 0) + return -EIO; + + tmp.section_bip = fore200e_swap(fore200e->stats->oc3.section_bip8_errors); + tmp.line_bip = fore200e_swap(fore200e->stats->oc3.line_bip24_errors); + tmp.path_bip = fore200e_swap(fore200e->stats->oc3.path_bip8_errors); + tmp.line_febe = fore200e_swap(fore200e->stats->oc3.line_febe_errors); + tmp.path_febe = fore200e_swap(fore200e->stats->oc3.path_febe_errors); + tmp.corr_hcs = fore200e_swap(fore200e->stats->oc3.corr_hcs_errors); + tmp.uncorr_hcs = fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors); + tmp.tx_cells = fore200e_swap(fore200e->stats->aal0.cells_transmitted) + + fore200e_swap(fore200e->stats->aal34.cells_transmitted) + + fore200e_swap(fore200e->stats->aal5.cells_transmitted); + tmp.rx_cells = fore200e_swap(fore200e->stats->aal0.cells_received) + + fore200e_swap(fore200e->stats->aal34.cells_received) + + fore200e_swap(fore200e->stats->aal5.cells_received); + + if (arg) + return copy_to_user(arg, &tmp, sizeof(struct sonet_stats)) ? -EFAULT : 0; + + return 0; +} + + +static int +fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg) +{ + struct fore200e* fore200e = FORE200E_DEV(dev); + + DPRINTK(2, "ioctl cmd = 0x%x (%u), arg = 0x%p (%lu)\n", cmd, cmd, arg, (unsigned long)arg); + + switch (cmd) { + + case SONET_GETSTAT: + return fore200e_fetch_stats(fore200e, (struct sonet_stats*)arg); + + case SONET_GETDIAG: + return put_user(0, (int*)arg) ? -EFAULT : 0; + + case SUNI_SETLOOP: + return fore200e_setloop(fore200e, (int)(unsigned long)arg); + + case SUNI_GETLOOP: + return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0; + } + + return -ENOSYS; /* not implemented */ +} + + +static int +fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags) +{ + struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); + struct fore200e* fore200e = FORE200E_DEV(vcc->dev); + + DPRINTK(2, "change_qos %d.%d.%d, " + "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " + "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n" + "available_cell_rate = %u", + vcc->itf, vcc->vpi, vcc->vci, + fore200e_traffic_class[ qos->txtp.traffic_class ], + qos->txtp.min_pcr, qos->txtp.max_pcr, qos->txtp.max_cdv, qos->txtp.max_sdu, + fore200e_traffic_class[ qos->rxtp.traffic_class ], + qos->rxtp.min_pcr, qos->rxtp.max_pcr, qos->rxtp.max_cdv, qos->rxtp.max_sdu, + flags, fore200e->available_cell_rate); + + if ((qos->txtp.traffic_class == ATM_CBR) && (qos->txtp.max_pcr > 0)) { + + down(&fore200e->rate_sf); + if (fore200e->available_cell_rate + vcc->qos.txtp.max_pcr < qos->txtp.max_pcr) { + up(&fore200e->rate_sf); + return -EAGAIN; + } + + fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; + fore200e->available_cell_rate -= qos->txtp.max_pcr; + up(&fore200e->rate_sf); + + memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); + + /* update rate control parameters */ + fore200e_rate_ctrl(qos, &fore200e_vcc->rate); + + vcc->flags |= ATM_VF_HASQOS; + return 0; + } + + return -EINVAL; +} + + +static int __init +fore200e_irq_request(struct fore200e* fore200e) +{ + if (request_irq(fore200e->irq, fore200e_interrupt, SA_SHIRQ, fore200e->name, fore200e->atm_dev) < 0) { + + printk(FORE200E "unable to reserve IRQ %s for device %s\n", + fore200e_irq_itoa(fore200e->irq), fore200e->name); + return -EBUSY; + } + + printk(FORE200E "IRQ %s reserved for device %s\n", + fore200e_irq_itoa(fore200e->irq), fore200e->name); + + fore200e->state = FORE200E_STATE_IRQ; + return 0; +} + + +static int __init +fore200e_get_esi(struct fore200e* fore200e) +{ + struct prom_data* prom = fore200e_kmalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA); + int ok, i; + + ok = fore200e->bus->prom_read(fore200e, prom); + if (ok < 0) + return -EBUSY; + + printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n", + fore200e->name, + (prom->hw_revision & 0xFF) + '@', /* probably meaningless with SBA boards */ + prom->serial_number & 0xFFFF, + prom->mac_addr[ 2 ], prom->mac_addr[ 3 ], prom->mac_addr[ 4 ], + prom->mac_addr[ 5 ], prom->mac_addr[ 6 ], prom->mac_addr[ 7 ]); + + for (i = 0; i < ESI_LEN; i++) { + fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ]; + } + + fore200e_kfree(prom); + + return 0; +} + + +static int __init +fore200e_alloc_rx_buf(struct fore200e* fore200e) +{ + int scheme, magn, nbr, size, i; + + struct host_bsq* bsq; + struct buffer* buffer; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + nbr = fore200e_rx_buf_nbr[ scheme ][ magn ]; + size = fore200e_rx_buf_size[ scheme ][ magn ]; + + DPRINTK(2, "rx buffers %d / %d are being allocated\n", scheme, magn); + + /* allocate the array of receive buffers */ + buffer = bsq->buffer = fore200e_kmalloc(nbr * sizeof(struct buffer), GFP_KERNEL); + + if (buffer == NULL) + return -ENOMEM; + + for (i = 0; i < nbr; i++) { + + buffer[ i ].scheme = scheme; + buffer[ i ].magn = magn; + + /* allocate the receive buffer body */ + if (fore200e_chunk_alloc(fore200e, + &buffer[ i ].data, size, fore200e->bus->buffer_alignment) < 0) { + + while (i > 0) + fore200e_chunk_free(fore200e, &buffer[ --i ].data); + fore200e_kfree(buffer); + + return -ENOMEM; + } + } + /* set next free buffer index */ + bsq->free = 0; + } + } + + fore200e->state = FORE200E_STATE_ALLOC_BUF; + return 0; +} + + +static int __init +fore200e_init_bs_queue(struct fore200e* fore200e) +{ + int scheme, magn, i; + + struct host_bsq* bsq; + struct cp_bsq_entry* cp_entry; + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { + + DPRINTK(2, "buffer supply queue %d / %d is being initialized\n", scheme, magn); + + bsq = &fore200e->host_bsq[ scheme ][ magn ]; + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &bsq->status, + sizeof(enum status), + QUEUE_SIZE_BS, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of receive buffer descriptors */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &bsq->rbd_block, + sizeof(struct rbd_block), + QUEUE_SIZE_BS, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_chunk_free(fore200e, &bsq->status); + return -ENOMEM; + } + + /* get the base address of the cp resident buffer supply queue entries */ + cp_entry = (struct cp_bsq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_bsq[ scheme ][ magn ])); + + /* fill the host resident and cp resident buffer supply queue entries */ + for (i = 0; i < QUEUE_SIZE_BS; i++) { + + bsq->host_entry[ i ].status = + FORE200E_INDEX(bsq->status.align_addr, enum status, i); + bsq->host_entry[ i ].rbd_block = + FORE200E_INDEX(bsq->rbd_block.align_addr, struct rbd_block, i); + bsq->host_entry[ i ].rbd_block_dma = + FORE200E_DMA_INDEX(bsq->rbd_block.dma_addr, struct rbd_block, i); + bsq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *bsq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(bsq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + } + } + } + + fore200e->state = FORE200E_STATE_INIT_BSQ; + return 0; +} + + +static int __init +fore200e_init_rx_queue(struct fore200e* fore200e) +{ + struct host_rxq* rxq = &fore200e->host_rxq; + struct cp_rxq_entry* cp_entry; + int i; + + DPRINTK(2, "receive queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &rxq->status, + sizeof(enum status), + QUEUE_SIZE_RX, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of receive PDU descriptors */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &rxq->rpd, + sizeof(struct rpd), + QUEUE_SIZE_RX, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_chunk_free(fore200e, &rxq->status); + return -ENOMEM; + } + + /* get the base address of the cp resident rx queue entries */ + cp_entry = (struct cp_rxq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_rxq)); + + /* fill the host resident and cp resident rx entries */ + for (i=0; i < QUEUE_SIZE_RX; i++) { + + rxq->host_entry[ i ].status = + FORE200E_INDEX(rxq->status.align_addr, enum status, i); + rxq->host_entry[ i ].rpd = + FORE200E_INDEX(rxq->rpd.align_addr, struct rpd, i); + rxq->host_entry[ i ].rpd_dma = + FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i); + rxq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *rxq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(rxq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + + fore200e->bus->write(FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i), + &cp_entry[ i ].rpd_haddr); + } + + /* set the head entry of the queue */ + rxq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_RXQ; + return 0; +} + + +static int __init +fore200e_init_tx_queue(struct fore200e* fore200e) +{ + struct host_txq* txq = &fore200e->host_txq; + struct cp_txq_entry* cp_entry; + int i; + + DPRINTK(2, "transmit queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &txq->status, + sizeof(enum status), + QUEUE_SIZE_TX, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* allocate and align the array of transmit PDU descriptors */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &txq->tpd, + sizeof(struct tpd), + QUEUE_SIZE_TX, + fore200e->bus->descr_alignment) < 0) { + + fore200e->bus->dma_chunk_free(fore200e, &txq->status); + return -ENOMEM; + } + + /* get the base address of the cp resident tx queue entries */ + cp_entry = (struct cp_txq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_txq)); + + /* fill the host resident and cp resident tx entries */ + for (i=0; i < QUEUE_SIZE_TX; i++) { + + txq->host_entry[ i ].status = + FORE200E_INDEX(txq->status.align_addr, enum status, i); + txq->host_entry[ i ].tpd = + FORE200E_INDEX(txq->tpd.align_addr, struct tpd, i); + txq->host_entry[ i ].tpd_dma = + FORE200E_DMA_INDEX(txq->tpd.dma_addr, struct tpd, i); + txq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *txq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(txq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + + /* although there is a one-to-one mapping of tx queue entries and tpds, + we do not write here the DMA (physical) base address of each tpd into + the related cp resident entry, because the cp relies on this write + operation to detect that a new pdu has been submitted for tx */ +} + + /* set the head entry of the queue */ + txq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_TXQ; + return 0; +} + + +static int __init +fore200e_init_cmd_queue(struct fore200e* fore200e) +{ + struct host_cmdq* cmdq = &fore200e->host_cmdq; + struct cp_cmdq_entry* cp_entry; + int i; + + DPRINTK(2, "command queue is being initialized\n"); + + /* allocate and align the array of status words */ + if (fore200e->bus->dma_chunk_alloc(fore200e, + &cmdq->status, + sizeof(enum status), + QUEUE_SIZE_CMD, + fore200e->bus->status_alignment) < 0) { + return -ENOMEM; + } + + /* get the base address of the cp resident cmd queue entries */ + cp_entry = (struct cp_cmdq_entry*)(fore200e->virt_base + + fore200e->bus->read(&fore200e->cp_queues->cp_cmdq)); + + /* fill the host resident and cp resident cmd entries */ + for (i=0; i < QUEUE_SIZE_CMD; i++) { + + cmdq->host_entry[ i ].status = + FORE200E_INDEX(cmdq->status.align_addr, enum status, i); + cmdq->host_entry[ i ].cp_entry = &cp_entry[ i ]; + + *cmdq->host_entry[ i ].status = STATUS_FREE; + + fore200e->bus->write(FORE200E_DMA_INDEX(cmdq->status.dma_addr, enum status, i), + &cp_entry[ i ].status_haddr); + } + + /* set the head entry of the queue */ + cmdq->head = 0; + + fore200e->state = FORE200E_STATE_INIT_CMDQ; + return 0; +} + + +static void __init +fore200e_param_bs_queue(struct fore200e* fore200e, + enum buffer_scheme scheme, enum buffer_magn magn, + int queue_length, int pool_size, int supply_blksize) +{ + struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ]; + + /* dumb value; the firmware doesn't allow us to activate a VC while + selecting a buffer scheme with zero-sized rbd pools */ + + if (pool_size == 0) + pool_size = 64; + + fore200e->bus->write(queue_length, &bs_spec->queue_length); + fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size); + fore200e->bus->write(pool_size, &bs_spec->pool_size); + fore200e->bus->write(supply_blksize, &bs_spec->supply_blksize); +} + + +static int __init +fore200e_initialize(struct fore200e* fore200e) +{ + struct cp_queues* cpq; + int ok, scheme, magn; + + DPRINTK(2, "device %s being initialized\n", fore200e->name); + + spin_lock_init(&fore200e->tx_lock); + init_MUTEX(&fore200e->rate_sf); + + cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET); + + /* enable cp to host interrupts */ + fore200e->bus->write(1, &cpq->imask); + + if (fore200e->bus->irq_enable) + fore200e->bus->irq_enable(fore200e); + + fore200e->bus->write(NBR_CONNECT, &cpq->init.num_connect); + + fore200e->bus->write(QUEUE_SIZE_CMD, &cpq->init.cmd_queue_len); + fore200e->bus->write(QUEUE_SIZE_RX, &cpq->init.rx_queue_len); + fore200e->bus->write(QUEUE_SIZE_TX, &cpq->init.tx_queue_len); + + fore200e->bus->write(RSD_EXTENSION, &cpq->init.rsd_extension); + fore200e->bus->write(TSD_EXTENSION, &cpq->init.tsd_extension); + + for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) + for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) + fore200e_param_bs_queue(fore200e, scheme, magn, + QUEUE_SIZE_BS, + fore200e_rx_buf_nbr[ scheme ][ magn ], + RBD_BLK_SIZE); + + /* issue the initialize command */ + fore200e->bus->write(STATUS_PENDING, &cpq->init.status); + fore200e->bus->write(OPCODE_INITIALIZE, &cpq->init.opcode); + + ok = fore200e_io_poll(fore200e, &cpq->init.status, STATUS_COMPLETE, 3000); + if (ok == 0) { + printk(FORE200E "device %s initialization failed\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s initialized\n", fore200e->name); + + fore200e->state = FORE200E_STATE_INITIALIZE; + return 0; +} + + +static void __init +fore200e_monitor_putc(struct fore200e* fore200e, char c) +{ + struct cp_monitor* monitor = fore200e->cp_monitor; + +#if 0 + printk("%c", c); +#endif + fore200e->bus->write(((u32) c) | FORE200E_CP_MONITOR_UART_AVAIL, &monitor->soft_uart.send); +} + + +static int __init +fore200e_monitor_getc(struct fore200e* fore200e) +{ + struct cp_monitor* monitor = fore200e->cp_monitor; + unsigned long timeout = jiffies + MSECS(50); + int c; + + while (jiffies < timeout) { + + c = (int) fore200e->bus->read(&monitor->soft_uart.recv); + + if (c & FORE200E_CP_MONITOR_UART_AVAIL) { + + fore200e->bus->write(FORE200E_CP_MONITOR_UART_FREE, &monitor->soft_uart.recv); +#if 0 + printk("%c", c & 0xFF); +#endif + return c & 0xFF; + } + } + + return -1; +} + + +static void __init +fore200e_monitor_puts(struct fore200e* fore200e, char* str) +{ + while(*str) { + + /* the i960 monitor doesn't accept any new character if it has something to say */ + while (fore200e_monitor_getc(fore200e) >= 0); + + fore200e_monitor_putc(fore200e, *str++); + } + + while (fore200e_monitor_getc(fore200e) >= 0); +} + + +static int __init +fore200e_start_fw(struct fore200e* fore200e) +{ + int ok; + char cmd[ 48 ]; + struct fw_header* fw_header = (struct fw_header*) fore200e->bus->fw_data; + + DPRINTK(2, "device %s firmware being started\n", fore200e->name); + + sprintf(cmd, "\rgo %x\r", le32_to_cpu(fw_header->start_offset)); + + fore200e_monitor_puts(fore200e, cmd); + + ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_CP_RUNNING, 1000); + if (ok == 0) { + printk(FORE200E "device %s firmware didn't start\n", fore200e->name); + return -ENODEV; + } + + printk(FORE200E "device %s firmware started\n", fore200e->name); + + fore200e->state = FORE200E_STATE_START_FW; + return 0; +} + + +static int __init +fore200e_load_fw(struct fore200e* fore200e) +{ + u32* fw_data = (u32*) fore200e->bus->fw_data; + u32 fw_size = (u32) *fore200e->bus->fw_size / sizeof(u32); + + struct fw_header* fw_header = (struct fw_header*) fw_data; + + u32* load_addr = fore200e->virt_base + le32_to_cpu(fw_header->load_offset); + + DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", + fore200e->name, load_addr, fw_size); + +#if 1 + if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) { + printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name); + return -ENODEV; + } +#endif + + for (; fw_size--; fw_data++, load_addr++) + fore200e->bus->write(le32_to_cpu(*fw_data), load_addr); + + fore200e->state = FORE200E_STATE_LOAD_FW; + return 0; +} + + +static int __init +fore200e_register(struct fore200e* fore200e) +{ + struct atm_dev* atm_dev; + + DPRINTK(2, "device %s being registered\n", fore200e->name); + + atm_dev = atm_dev_register(fore200e->bus->proc_name, &fore200e_ops, -1, 0); + if (atm_dev == NULL) { + printk(FORE200E "unable to register device %s\n", fore200e->name); + return -ENODEV; + } + + FORE200E_DEV(atm_dev) = fore200e; + fore200e->atm_dev = atm_dev; + + atm_dev->ci_range.vpi_bits = 8; + atm_dev->ci_range.vci_bits = 10; + + fore200e->available_cell_rate = ATM_OC3_PCR; + + fore200e->state = FORE200E_STATE_REGISTER; + return 0; +} + + +static int __init +fore200e_init(struct fore200e* fore200e) +{ + if (fore200e_register(fore200e) < 0) + return -ENODEV; + + if (fore200e->bus->configure(fore200e) < 0) + return -ENODEV; + + if (fore200e->bus->map(fore200e) < 0) + return -ENODEV; + + if (fore200e_reset(fore200e, 1) < 0) + return -ENODEV; + + if (fore200e_load_fw(fore200e) < 0) + return -ENODEV; + + if (fore200e_start_fw(fore200e) < 0) + return -ENODEV; + + if (fore200e_initialize(fore200e) < 0) + return -ENODEV; + + if (fore200e_init_cmd_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_tx_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_rx_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_init_bs_queue(fore200e) < 0) + return -ENOMEM; + + if (fore200e_alloc_rx_buf(fore200e) < 0) + return -ENOMEM; + + if (fore200e_get_esi(fore200e) < 0) + return -EIO; + + if (fore200e_irq_request(fore200e) < 0) + return -EBUSY; + + fore200e_supply(fore200e); + + /* all done, board initialization is now complete */ + fore200e->state = FORE200E_STATE_COMPLETE; + return 0; +} + + +int __init +fore200e_detect(void) +{ + const struct fore200e_bus* bus; + struct fore200e* fore200e; + int index, link; + + printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n"); + + /* for each configured bus interface */ + for (link = 0, bus = fore200e_bus; bus->model_name; bus++) { + + /* detect all boards present on that bus */ + for (index = 0; (fore200e = bus->detect(bus, index)); index++) { + + printk(FORE200E "device %s found at 0x%lx, IRQ %s\n", + fore200e->bus->model_name, + fore200e->phys_base, fore200e_irq_itoa(fore200e->irq)); + + sprintf(fore200e->name, "%s-%d", bus->model_name, index); + + if (fore200e_init(fore200e) < 0) { + + fore200e_shutdown(fore200e); + break; + } + + link++; + + fore200e->next = fore200e_boards; + fore200e_boards = fore200e; + } + } + +#if 0 /* XXX uncomment this to forbid module unloading */ +#ifdef MODULE + if (link > 0) + MOD_INC_USE_COUNT; +#endif +#endif + + return link; +} + + +#ifdef MODULE +static void +fore200e_cleanup(struct fore200e** head) +{ + struct fore200e* fore200e = *head; + + fore200e_shutdown(fore200e); + + *head = fore200e->next; + + kfree(fore200e); +} +#endif + + +static int +fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) +{ + struct fore200e* fore200e = FORE200E_DEV(dev); + int len, left = *pos; + + if (!left--) { + + if (fore200e_getstats(fore200e) < 0) + return -EIO; + + len = sprintf(page,"\n" + " device:\n" + " internal name:\t\t%s\n", fore200e->name); + + /* print bus-specific information */ + if (fore200e->bus->proc_read) + len += fore200e->bus->proc_read(fore200e, page + len); + + len += sprintf(page + len, + " interrupt line:\t\t%s\n" + " physical base address:\t0x%p\n" + " virtual base address:\t0x%p\n" + " factory address (ESI):\t%02x:%02x:%02x:%02x:%02x:%02x\n" + " board serial number:\t\t%d\n\n", + fore200e_irq_itoa(fore200e->irq), + (void*)fore200e->phys_base, + (void*)fore200e->virt_base, + fore200e->esi[0], fore200e->esi[1], fore200e->esi[2], + fore200e->esi[3], fore200e->esi[4], fore200e->esi[5], + fore200e->esi[4] * 256 + fore200e->esi[5]); + + return len; + } + + if (!left--) + return sprintf(page, + " supplied small bufs (1):\t%d\n" + " supplied large bufs (1):\t%d\n" + " supplied small bufs (2):\t%d\n" + " supplied large bufs (2):\t%d\n", + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].count, + fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].count, + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].count, + fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].count); + if (!left--) { + u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat); + + len = sprintf(page,"\n\n" + " cell processor:\n" + " heartbeat state:\t\t"); + + if (hb >> 16 != 0xDEAD) + len += sprintf(page + len, "0x%08x\n", hb); + else + len += sprintf(page + len, "*** FATAL ERROR %04x ***\n", hb & 0xFFFF); + + return len; + } + + if (!left--) { + static const char* media_name[] = { + "unshielded twisted pair", + "multimode optical fiber ST", + "multimode optical fiber SC", + "single-mode optical fiber ST", + "single-mode optical fiber SC", + "unknown" + }; + + static const char* oc3_mode[] = { + "normal operation", + "diagnostic loopback", + "line loopback" + }; + + u32 fw_release = fore200e->bus->read(&fore200e->cp_queues->fw_release); + u32 mon960_release = fore200e->bus->read(&fore200e->cp_queues->mon960_release); + u32 oc3_revision = fore200e->bus->read(&fore200e->cp_queues->oc3_revision); + u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type)); + + if (media_index < 0 || media_index > 4) + media_index = 5; + + return sprintf(page, + " firmware release:\t\t%d.%d.%d\n" + " monitor release:\t\t%d.%d\n" + " media type:\t\t\t%s\n" + " OC-3 revision:\t\t0x%x\n" + " OC-3 mode:\t\t\t%s", + fw_release >> 16, fw_release << 16 >> 24, fw_release << 24 >> 24, + mon960_release >> 16, mon960_release << 16 >> 16, + media_name[ media_index ], + oc3_revision, + oc3_mode[ fore200e->loop_mode ]); + } + + if (!left--) { + struct cp_monitor* cp_monitor = fore200e->cp_monitor; + + return sprintf(page, + "\n\n" + " monitor:\n" + " version number:\t\t%d\n" + " boot status word:\t\t0x%08x\n", + fore200e->bus->read(&cp_monitor->mon_version), + fore200e->bus->read(&cp_monitor->bstat)); + } + + if (!left--) + return sprintf(page, + "\n" + " device statistics:\n" + " 4b5b:\n" + " crc_header_errors:\t\t%10u\n" + " framing_errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->phy.crc_header_errors), + fore200e_swap(fore200e->stats->phy.framing_errors)); + + if (!left--) + return sprintf(page, "\n" + " OC-3:\n" + " section_bip8_errors:\t%10u\n" + " path_bip8_errors:\t\t%10u\n" + " line_bip24_errors:\t\t%10u\n" + " line_febe_errors:\t\t%10u\n" + " path_febe_errors:\t\t%10u\n" + " corr_hcs_errors:\t\t%10u\n" + " ucorr_hcs_errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->oc3.section_bip8_errors), + fore200e_swap(fore200e->stats->oc3.path_bip8_errors), + fore200e_swap(fore200e->stats->oc3.line_bip24_errors), + fore200e_swap(fore200e->stats->oc3.line_febe_errors), + fore200e_swap(fore200e->stats->oc3.path_febe_errors), + fore200e_swap(fore200e->stats->oc3.corr_hcs_errors), + fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors)); + + if (!left--) + return sprintf(page,"\n" + " ATM:\t\t\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " vpi out of range:\t\t%10u\n" + " vpi no conn:\t\t%10u\n" + " vci out of range:\t\t%10u\n" + " vci no conn:\t\t%10u\n", + fore200e_swap(fore200e->stats->atm.cells_transmitted), + fore200e_swap(fore200e->stats->atm.cells_received), + fore200e_swap(fore200e->stats->atm.vpi_bad_range), + fore200e_swap(fore200e->stats->atm.vpi_no_conn), + fore200e_swap(fore200e->stats->atm.vci_bad_range), + fore200e_swap(fore200e->stats->atm.vci_no_conn)); + + if (!left--) + return sprintf(page,"\n" + " AAL0:\t\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n", + fore200e_swap(fore200e->stats->aal0.cells_transmitted), + fore200e_swap(fore200e->stats->aal0.cells_received), + fore200e_swap(fore200e->stats->aal0.cells_dropped)); + + if (!left--) + return sprintf(page,"\n" + " AAL3/4:\n" + " SAR sublayer:\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " CRC errors:\t\t%10u\n" + " protocol errors:\t\t%10u\n\n" + " CS sublayer:\t\t PDUs\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " protocol errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->aal34.cells_transmitted), + fore200e_swap(fore200e->stats->aal34.cells_received), + fore200e_swap(fore200e->stats->aal34.cells_dropped), + fore200e_swap(fore200e->stats->aal34.cells_crc_errors), + fore200e_swap(fore200e->stats->aal34.cells_protocol_errors), + fore200e_swap(fore200e->stats->aal34.cspdus_transmitted), + fore200e_swap(fore200e->stats->aal34.cspdus_received), + fore200e_swap(fore200e->stats->aal34.cspdus_dropped), + fore200e_swap(fore200e->stats->aal34.cspdus_protocol_errors)); + + if (!left--) + return sprintf(page,"\n" + " AAL5:\n" + " SAR sublayer:\t\t cells\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " congestions:\t\t%10u\n\n" + " CS sublayer:\t\t PDUs\n" + " TX:\t\t\t%10u\n" + " RX:\t\t\t%10u\n" + " dropped:\t\t\t%10u\n" + " CRC errors:\t\t%10u\n" + " protocol errors:\t\t%10u\n", + fore200e_swap(fore200e->stats->aal5.cells_transmitted), + fore200e_swap(fore200e->stats->aal5.cells_received), + fore200e_swap(fore200e->stats->aal5.cells_dropped), + fore200e_swap(fore200e->stats->aal5.congestion_experienced), + fore200e_swap(fore200e->stats->aal5.cspdus_transmitted), + fore200e_swap(fore200e->stats->aal5.cspdus_received), + fore200e_swap(fore200e->stats->aal5.cspdus_dropped), + fore200e_swap(fore200e->stats->aal5.cspdus_crc_errors), + fore200e_swap(fore200e->stats->aal5.cspdus_protocol_errors)); + + if (!left--) + return sprintf(page,"\n" + " AUX:\t\t allocation failures\n" + " small b1:\t\t\t%10u\n" + " large b1:\t\t\t%10u\n" + " small b2:\t\t\t%10u\n" + " large b2:\t\t\t%10u\n" + " RX PDUs:\t\t\t%10u\n", + fore200e_swap(fore200e->stats->aux.small_b1_failed), + fore200e_swap(fore200e->stats->aux.large_b1_failed), + fore200e_swap(fore200e->stats->aux.small_b2_failed), + fore200e_swap(fore200e->stats->aux.large_b2_failed), + fore200e_swap(fore200e->stats->aux.rpd_alloc_failed)); + + if (!left--) + return sprintf(page,"\n" + " receive carrier:\t\t\t%s\n", + fore200e->stats->aux.receive_carrier ? "ON" : "OFF!"); + + if (!left--) { + struct atm_vcc *vcc; + struct fore200e_vcc* fore200e_vcc; + + len = sprintf(page,"\n" + " VCCs:\n address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n"); + + for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { + + fore200e_vcc = FORE200E_VCC(vcc); + + len += sprintf(page + len, + " %x\t%d.%d:%d\t\t(%d/%d)\t(%d/%d)\n", + (u32)(unsigned long)vcc, + vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), + fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu, + fore200e_vcc->tx_max_pdu, + fore200e_vcc->rx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->rx_min_pdu, + fore200e_vcc->rx_max_pdu + ); + } + + return len; + } + + return 0; +} + + +#ifdef MODULE +unsigned int +init_module(void) +{ + DPRINTK(1, "module loaded\n"); + return fore200e_detect() == 0; +} + +void +cleanup_module(void) +{ + while (fore200e_boards) { + fore200e_cleanup(&fore200e_boards); + } + DPRINTK(1, "module being removed\n"); +} +#endif + + +static const struct atmdev_ops fore200e_ops = +{ + NULL, /* fore200e_dev_close */ + fore200e_open, + fore200e_close, + fore200e_ioctl, + fore200e_getsockopt, + fore200e_setsockopt, + fore200e_send, + NULL, /* fore200e_sg_send, */ + NULL, /* fore200e_send_oam, */ + NULL, /* fore200e_phy_put, */ + NULL, /* fore200e_phy_get, */ + NULL, /* fore200e_feedback, */ + fore200e_change_qos, + NULL, /* fore200e_free_rx_skb */ + fore200e_proc_read +}; + + +#ifdef CONFIG_ATM_FORE200E_PCA +extern const unsigned char _fore200e_pca_fw_data[]; +extern const unsigned int _fore200e_pca_fw_size; +#endif +#ifdef CONFIG_ATM_FORE200E_SBA +extern const unsigned char _fore200e_sba_fw_data[]; +extern const unsigned int _fore200e_sba_fw_size; +#endif + +static const struct fore200e_bus fore200e_bus[] = { +#ifdef CONFIG_ATM_FORE200E_PCA + { "PCA-200E", "pca200e", 32, 4, 32, + _fore200e_pca_fw_data, &_fore200e_pca_fw_size, + fore200e_pca_read, + fore200e_pca_write, + fore200e_pca_dma_map, + fore200e_pca_dma_unmap, + fore200e_pca_dma_sync, + fore200e_pca_dma_chunk_alloc, + fore200e_pca_dma_chunk_free, + fore200e_pca_detect, + fore200e_pca_configure, + fore200e_pca_map, + fore200e_pca_reset, + fore200e_pca_prom_read, + fore200e_pca_unmap, + NULL, + fore200e_pca_irq_check, + fore200e_pca_irq_ack, + fore200e_pca_proc_read, + }, +#endif +#ifdef CONFIG_ATM_FORE200E_SBA + { "SBA-200E", "sba200e", 32, 64, 32, + _fore200e_sba_fw_data, &_fore200e_sba_fw_size, + fore200e_sba_read, + fore200e_sba_write, + fore200e_sba_dma_map, + fore200e_sba_dma_unmap, + fore200e_sba_dma_sync, + fore200e_sba_dma_chunk_alloc, + fore200e_sba_dma_chunk_free, + fore200e_sba_detect, + fore200e_sba_configure, + fore200e_sba_map, + fore200e_sba_reset, + fore200e_sba_prom_read, + fore200e_sba_unmap, + fore200e_sba_irq_enable, + fore200e_sba_irq_check, + fore200e_sba_irq_ack, + fore200e_sba_proc_read, + }, +#endif + {} +}; diff -u --recursive --new-file v2.3.47/linux/drivers/atm/fore200e.h linux/drivers/atm/fore200e.h --- v2.3.47/linux/drivers/atm/fore200e.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/fore200e.h Mon Feb 21 16:32:27 2000 @@ -0,0 +1,952 @@ +#ifndef _FORE200E_H +#define _FORE200E_H + +#ifdef __KERNEL__ + +/* rx buffer sizes */ + +#define SMALL_BUFFER_SIZE 384 /* size of small buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ +#define LARGE_BUFFER_SIZE 4032 /* size of large buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ + + +#define RBD_BLK_SIZE 32 /* nbr of supplied rx buffers per rbd */ + + +#define MAX_PDU_SIZE 65535 /* maximum PDU size supported by AALs */ + + +#define BUFFER_S1_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 1 */ +#define BUFFER_L1_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 1 */ + +#define BUFFER_S2_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 2 */ +#define BUFFER_L2_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 2 */ + +#define BUFFER_S1_NBR (RBD_BLK_SIZE * 2) +#define BUFFER_L1_NBR (RBD_BLK_SIZE * 2) + +#define BUFFER_S2_NBR (RBD_BLK_SIZE * 2) +#define BUFFER_L2_NBR (RBD_BLK_SIZE * 2) + + +#define QUEUE_SIZE_CMD 16 /* command queue capacity */ +#define QUEUE_SIZE_RX 64 /* receive queue capacity */ +#define QUEUE_SIZE_TX 256 /* transmit queue capacity */ +#define QUEUE_SIZE_BS 16 /* buffer supply queue capacity */ + +#define NBR_CONNECT 1024 /* number of ATM connections */ + + +#define TSD_FIXED 2 +#define TSD_EXTENSION 0 +#define TSD_NBR (TSD_FIXED + TSD_EXTENSION) + + +/* the cp starts putting a received PDU into one *small* buffer, + then it uses a number of *large* buffers for the trailing data. + we compute here the total number of receive segment descriptors + required to hold the largest possible PDU */ + +#define RSD_REQUIRED (((MAX_PDU_SIZE - SMALL_BUFFER_SIZE + LARGE_BUFFER_SIZE) / LARGE_BUFFER_SIZE) + 1) + +#define RSD_FIXED 3 + +/* RSD_REQUIRED receive segment descriptors are enough to describe a max-sized PDU, + but we have to keep the size of the receive PDU descriptor multiple of 32 bytes, + so we add one extra RSD to RSD_EXTENSION + (WARNING: THIS MAY CHANGE IF BUFFER SIZES ARE MODIFIED) */ + +#define RSD_EXTENSION ((RSD_REQUIRED - RSD_FIXED) + 1) +#define RSD_NBR (RSD_FIXED + RSD_EXTENSION) + + +#define FORE200E_DEV(d) ((struct fore200e*)((d)->dev_data)) +#define FORE200E_VCC(d) ((struct fore200e_vcc*)((d)->dev_data)) + +/* bitfields endian games */ + +#if defined(__LITTLE_ENDIAN_BITFIELD) +#define BITFIELD2(b1, b2) b1; b2; +#define BITFIELD3(b1, b2, b3) b1; b2; b3; +#define BITFIELD4(b1, b2, b3, b4) b1; b2; b3; b4; +#define BITFIELD5(b1, b2, b3, b4, b5) b1; b2; b3; b4; b5; +#define BITFIELD6(b1, b2, b3, b4, b5, b6) b1; b2; b3; b4; b5; b6; +#elif defined(__BIG_ENDIAN_BITFIELD) +#define BITFIELD2(b1, b2) b2; b1; +#define BITFIELD3(b1, b2, b3) b3; b2; b1; +#define BITFIELD4(b1, b2, b3, b4) b4; b3; b2; b1; +#define BITFIELD5(b1, b2, b3, b4, b5) b5; b4; b3; b2; b1; +#define BITFIELD6(b1, b2, b3, b4, b5, b6) b6; b5; b4; b3; b2; b1; +#else +#error unknown bitfield endianess +#endif + + +/* ATM cell header (minus HEC byte) */ + +typedef struct atm_header { + BITFIELD5( + u32 clp : 1, /* cell loss priority */ + u32 plt : 3, /* payload type */ + u32 vci : 16, /* virtual channel identifier */ + u32 vpi : 8, /* virtual path identifier */ + u32 gfc : 4 /* generic flow control */ + ) +} atm_header_t; + + +/* ATM adaptation layer id */ + +typedef enum fore200e_aal { + FORE200E_AAL0 = 0, + FORE200E_AAL34 = 4, + FORE200E_AAL5 = 5, +} fore200e_aal_t; + + +/* transmit PDU descriptor specification */ + +typedef struct tpd_spec { + BITFIELD4( + u32 length : 16, /* total PDU length */ + u32 nseg : 8, /* number of transmit segments */ + enum fore200e_aal aal : 4, /* adaptation layer */ + u32 intr : 4 /* interrupt requested */ + ) +} tpd_spec_t; + + +/* transmit PDU rate control */ + +typedef struct tpd_rate +{ + BITFIELD2( + u32 idle_cells : 16, /* number of idle cells to insert */ + u32 data_cells : 16 /* number of data cells to transmit */ + ) +} tpd_rate_t; + + +/* transmit segment descriptor */ + +typedef struct tsd { + u32 buffer; /* transmit buffer DMA address */ + u32 length; /* number of bytes in buffer */ +} tsd_t; + + +/* transmit PDU descriptor */ + +typedef struct tpd { + struct atm_header atm_header; /* ATM header minus HEC byte */ + struct tpd_spec spec; /* tpd specification */ + struct tpd_rate rate; /* tpd rate control */ + u32 pad; /* reserved */ + struct tsd tsd[ TSD_NBR ]; /* transmit segment descriptors */ +} tpd_t; + + +/* receive segment descriptor */ + +typedef struct rsd { + u32 handle; /* host supplied receive buffer handle */ + u32 length; /* number of bytes in buffer */ +} rsd_t; + + +/* receive PDU descriptor */ + +typedef struct rpd { + struct atm_header atm_header; /* ATM header minus HEC byte */ + u32 nseg; /* number of receive segments */ + struct rsd rsd[ RSD_NBR ]; /* receive segment descriptors */ +} rpd_t; + + +/* buffer scheme */ + +typedef enum buffer_scheme { + BUFFER_SCHEME_ONE, + BUFFER_SCHEME_TWO, + BUFFER_SCHEME_NBR /* always last */ +} buffer_scheme_t; + + +/* buffer magnitude */ + +typedef enum buffer_magn { + BUFFER_MAGN_SMALL, + BUFFER_MAGN_LARGE, + BUFFER_MAGN_NBR /* always last */ +} buffer_magn_t; + + +/* receive buffer descriptor */ + +typedef struct rbd { + u32 handle; /* host supplied handle */ + u32 buffer_haddr; /* host DMA address of host buffer */ +} rbd_t; + + +/* receive buffer descriptor block */ + +typedef struct rbd_block { + struct rbd rbd[ RBD_BLK_SIZE ]; /* receive buffer descriptor */ +} rbd_block_t; + + +/* tpd DMA address */ + +typedef struct tpd_haddr { + BITFIELD3( + u32 size : 4, /* tpd size expressed in 32 byte blocks */ + u32 pad : 1, /* reserved */ + u32 haddr : 27 /* tpd DMA addr aligned on 32 byte boundary */ + ) +} tpd_haddr_t; + + +/* cp resident transmit queue entry */ + +typedef struct cp_txq_entry { + struct tpd_haddr tpd_haddr; /* host DMA address of tpd */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_txq_entry_t; + + +/* cp resident receive queue entry */ + +typedef struct cp_rxq_entry { + u32 rpd_haddr; /* host DMA address of rpd */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_rxq_entry_t; + + +/* cp resident buffer supply queue entry */ + +typedef struct cp_bsq_entry { + u32 rbd_block_haddr; /* host DMA address of rbd block */ + u32 status_haddr; /* host DMA address of completion status */ +} cp_bsq_entry_t; + + +/* completion status */ + +typedef volatile enum status { + STATUS_PENDING = (1<<0), /* initial status (written by host) */ + STATUS_COMPLETE = (1<<1), /* completion status (written by cp) */ + STATUS_FREE = (1<<2), /* initial status (written by host) */ + STATUS_ERROR = (1<<3) /* completion status (written by cp) */ +} status_t; + + +/* cp operation code */ + +typedef enum opcode { + OPCODE_INITIALIZE = 1, /* initialize board */ + OPCODE_ACTIVATE_VCIN, /* activate incoming VCI */ + OPCODE_ACTIVATE_VCOUT, /* activate outgoing VCI */ + OPCODE_DEACTIVATE_VCIN, /* deactivate incoming VCI */ + OPCODE_DEACTIVATE_VCOUT, /* deactivate incoing VCI */ + OPCODE_GET_STATS, /* get board statistics */ + OPCODE_SET_OC3, /* set OC-3 registers */ + OPCODE_GET_OC3, /* get OC-3 registers */ + OPCODE_RESET_STATS, /* reset board statistics */ + OPCODE_GET_PROM, /* get expansion PROM data (PCI specific) */ + OPCODE_SET_VPI_BITS, /* set x bits of those decoded by the + firmware to be low order bits from + the VPI field of the ATM cell header */ + OPCODE_REQUEST_INTR = (1<<7) /* request interrupt */ +} opcode_t; + + +/* virtual path / virtual channel identifers */ + +typedef struct vpvc { + BITFIELD3( + u32 vci : 16, /* virtual channel identifier */ + u32 vpi : 8, /* virtual path identifier */ + u32 pad : 8 /* reserved */ + ) +} vpvc_t; + + +/* activate VC command opcode */ + +typedef struct activate_opcode { + BITFIELD4( + enum opcode opcode : 8, /* cp opcode */ + enum fore200e_aal aal : 8, /* adaptation layer */ + enum buffer_scheme scheme : 8, /* buffer scheme */ + u32 pad : 8 /* reserved */ + ) +} activate_opcode_t; + + +/* activate VC command block */ + +typedef struct activate_block { + struct activate_opcode opcode; /* activate VC command opcode */ + struct vpvc vpvc; /* VPI/VCI */ + u32 mtu; /* for AAL0 only */ + +} activate_block_t; + + +/* deactivate VC command opcode */ + +typedef struct deactivate_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} deactivate_opcode_t; + + +/* deactivate VC command block */ + +typedef struct deactivate_block { + struct deactivate_opcode opcode; /* deactivate VC command opcode */ + struct vpvc vpvc; /* VPI/VCI */ +} deactivate_block_t; + + +/* OC-3 registers */ + +typedef struct oc3_regs { + u32 reg[ 128 ]; /* see the PMC Sierra PC5346 S/UNI-155-Lite + Saturn User Network Interface documentation + for a description of the OC-3 chip registers */ +} oc3_regs_t; + + +/* set/get OC-3 regs command opcode */ + +typedef struct oc3_opcode { + BITFIELD4( + enum opcode opcode : 8, /* cp opcode */ + u32 reg : 8, /* register index */ + u32 value : 8, /* register value */ + u32 mask : 8 /* register mask that specifies which + bits of the register value field + are significant */ + ) +} oc3_opcode_t; + + +/* set/get OC-3 regs command block */ + +typedef struct oc3_block { + struct oc3_opcode opcode; /* set/get OC-3 regs command opcode */ + u32 regs_haddr; /* host DMA address of OC-3 regs buffer */ +} oc3_block_t; + + +/* physical encoding statistics */ + +typedef struct stats_phy { + u32 crc_header_errors; /* cells received with bad header CRC */ + u32 framing_errors; /* cells received with bad framing */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_phy_t; + + +/* OC-3 statistics */ + +typedef struct stats_oc3 { + u32 section_bip8_errors; /* section 8 bit interleaved parity */ + u32 path_bip8_errors; /* path 8 bit interleaved parity */ + u32 line_bip24_errors; /* line 24 bit interleaved parity */ + u32 line_febe_errors; /* line far end block errors */ + u32 path_febe_errors; /* path far end block errors */ + u32 corr_hcs_errors; /* correctable header check sequence */ + u32 ucorr_hcs_errors; /* uncorrectable header check sequence */ + u32 pad[ 1 ]; /* i960 padding */ +} stats_oc3_t; + + +/* ATM statistics */ + +typedef struct stats_atm { + u32 cells_transmitted; /* cells transmitted */ + u32 cells_received; /* cells received */ + u32 vpi_bad_range; /* cell drops: VPI out of range */ + u32 vpi_no_conn; /* cell drops: no connection for VPI */ + u32 vci_bad_range; /* cell drops: VCI out of range */ + u32 vci_no_conn; /* cell drops: no connection for VCI */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_atm_t; + +/* AAL0 statistics */ + +typedef struct stats_aal0 { + u32 cells_transmitted; /* cells transmitted */ + u32 cells_received; /* cells received */ + u32 cells_dropped; /* cells dropped */ + u32 pad[ 1 ]; /* i960 padding */ +} stats_aal0_t; + + +/* AAL3/4 statistics */ + +typedef struct stats_aal34 { + u32 cells_transmitted; /* cells transmitted from segmented PDUs */ + u32 cells_received; /* cells reassembled into PDUs */ + u32 cells_crc_errors; /* payload CRC error count */ + u32 cells_protocol_errors; /* SAR or CS layer protocol errors */ + u32 cells_dropped; /* cells dropped: partial reassembly */ + u32 cspdus_transmitted; /* CS PDUs transmitted */ + u32 cspdus_received; /* CS PDUs received */ + u32 cspdus_protocol_errors; /* CS layer protocol errors */ + u32 cspdus_dropped; /* reassembled PDUs drop'd (in cells) */ + u32 pad[ 3 ]; /* i960 padding */ +} stats_aal34_t; + + +/* AAL5 statistics */ + +typedef struct stats_aal5 { + u32 cells_transmitted; /* cells transmitted from segmented SDUs */ + u32 cells_received; /* cells reassembled into SDUs */ + u32 cells_dropped; /* reassembled PDUs dropped (in cells) */ + u32 congestion_experienced; /* CRC error and length wrong */ + u32 cspdus_transmitted; /* CS PDUs transmitted */ + u32 cspdus_received; /* CS PDUs received */ + u32 cspdus_crc_errors; /* CS PDUs CRC errors */ + u32 cspdus_protocol_errors; /* CS layer protocol errors */ + u32 cspdus_dropped; /* reassembled PDUs dropped */ + u32 pad[ 3 ]; /* i960 padding */ +} stats_aal5_t; + + +/* auxiliary statistics */ + +typedef struct stats_aux { + u32 small_b1_failed; /* receive BD allocation failures */ + u32 large_b1_failed; /* receive BD allocation failures */ + u32 small_b2_failed; /* receive BD allocation failures */ + u32 large_b2_failed; /* receive BD allocation failures */ + u32 rpd_alloc_failed; /* receive PDU allocation failures */ + u32 receive_carrier; /* no carrier = 0, carrier = 1 */ + u32 pad[ 2 ]; /* i960 padding */ +} stats_aux_t; + + +/* whole statistics buffer */ + +typedef struct stats { + struct stats_phy phy; /* physical encoding statistics */ + struct stats_oc3 oc3; /* OC-3 statistics */ + struct stats_atm atm; /* ATM statistics */ + struct stats_aal0 aal0; /* AAL0 statistics */ + struct stats_aal34 aal34; /* AAL3/4 statistics */ + struct stats_aal5 aal5; /* AAL5 statistics */ + struct stats_aux aux; /* auxiliary statistics */ +} stats_t; + + +/* get statistics command opcode */ + +typedef struct stats_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} stats_opcode_t; + + +/* get statistics command block */ + +typedef struct stats_block { + struct stats_opcode opcode; /* get statistics command opcode */ + u32 stats_haddr; /* host DMA address of stats buffer */ +} stats_block_t; + + +/* expansion PROM data (PCI specific) */ + +typedef struct prom_data { + u32 hw_revision; /* hardware revision */ + u32 serial_number; /* board serial number */ + u8 mac_addr[ 8 ]; /* board MAC address */ +} prom_data_t; + + +/* get expansion PROM data command opcode */ + +typedef struct prom_opcode { + BITFIELD2( + enum opcode opcode : 8, /* cp opcode */ + u32 pad : 24 /* reserved */ + ) +} prom_opcode_t; + + +/* get expansion PROM data command block */ + +typedef struct prom_block { + struct prom_opcode opcode; /* get PROM data command opcode */ + u32 prom_haddr; /* host DMA address of PROM buffer */ +} prom_block_t; + + +/* cp command */ + +typedef union cmd { + enum opcode opcode; /* operation code */ + struct activate_block activate_block; /* activate VC */ + struct deactivate_block deactivate_block; /* deactivate VC */ + struct stats_block stats_block; /* get statistics */ + struct prom_block prom_block; /* get expansion PROM data */ + struct oc3_block oc3_block; /* get/set OC-3 registers */ + u32 pad[ 4 ]; /* i960 padding */ +} cmd_t; + + +/* cp resident command queue */ + +typedef struct cp_cmdq_entry { + union cmd cmd; /* command */ + u32 status_haddr; /* host DMA address of completion status */ + u32 pad[ 3 ]; /* i960 padding */ +} cp_cmdq_entry_t; + + +/* host resident transmit queue entry */ + +typedef struct host_txq_entry { + struct cp_txq_entry* cp_entry; /* addr of cp resident tx queue entry */ + enum status* status; /* addr of host resident status */ + struct tpd* tpd; /* addr of transmit PDU descriptor */ + u32 tpd_dma; /* DMA address of tpd */ + struct sk_buff* skb; /* related skb */ + struct atm_vcc* vcc; /* related vcc */ + void* data; /* copy of misaligned data */ +} host_txq_entry_t; + + +/* host resident receive queue entry */ + +typedef struct host_rxq_entry { + struct cp_rxq_entry* cp_entry; /* addr of cp resident rx queue entry */ + enum status* status; /* addr of host resident status */ + struct rpd* rpd; /* addr of receive PDU descriptor */ + u32 rpd_dma; /* DMA address of rpd */ +} host_rxq_entry_t; + + +/* host resident buffer supply queue entry */ + +typedef struct host_bsq_entry { + struct cp_bsq_entry* cp_entry; /* addr of cp resident buffer supply queue entry */ + enum status* status; /* addr of host resident status */ + struct rbd_block* rbd_block; /* addr of receive buffer descriptor block */ + u32 rbd_block_dma; /* DMA address od rdb */ +} host_bsq_entry_t; + + +/* host resident command queue entry */ + +typedef struct host_cmdq_entry { + struct cp_cmdq_entry* cp_entry; /* addr of cp resident cmd queue entry */ + enum status* status; /* addr of host resident status */ +} host_cmdq_entry_t; + + +/* chunk of memory */ + +typedef struct chunk { + void* alloc_addr; /* base address of allocated chunk */ + void* align_addr; /* base address of aligned chunk */ + u32 dma_addr; /* DMA address of aligned chunk */ + u32 alloc_size; /* length of allocated chunk */ + u32 align_size; /* length of aligned chunk */ +} chunk_t; + +#define dma_size align_size /* DMA useable size */ + + +/* host resident receive buffer */ + +typedef struct buffer { + struct buffer* next; /* next receive buffer */ + enum buffer_scheme scheme; /* buffer scheme */ + enum buffer_magn magn; /* buffer magnitude */ + struct chunk data; /* data buffer */ +} buffer_t; + + +#if (BITS_PER_LONG == 32) +#define FORE200E_BUF2HDL(buffer) ((u32)(buffer)) +#define FORE200E_HDL2BUF(handle) ((struct buffer*)(handle)) +#else /* deal with 64 bit pointers */ +#define FORE200E_BUF2HDL(buffer) ((u32)((u64)(buffer))) +#define FORE200E_HDL2BUF(handle) ((struct buffer*)(((u64)(handle)) | PAGE_OFFSET)) +#endif + + +/* host resident command queue */ + +typedef struct host_cmdq { + struct host_cmdq_entry host_entry[ QUEUE_SIZE_CMD ]; /* host resident cmd queue entries */ + int head; /* head of cmd queue */ + struct chunk status; /* array of completion status */ +} host_cmdq_t; + + +/* host resident transmit queue */ + +typedef struct host_txq { + struct host_txq_entry host_entry[ QUEUE_SIZE_TX ]; /* host resident tx queue entries */ + int head; /* head of tx queue */ + struct chunk tpd; /* array of tpds */ + struct chunk status; /* arry of completion status */ + int txing; /* number of pending PDUs in tx queue */ +} host_txq_t; + + +/* host resident receive queue */ + +typedef struct host_rxq { + struct host_rxq_entry host_entry[ QUEUE_SIZE_RX ]; /* host resident rx queue entries */ + int head; /* head of rx queue */ + struct chunk rpd; /* array of rpds */ + struct chunk status; /* array of completion status */ +} host_rxq_t; + + +/* host resident buffer supply queues */ + +typedef struct host_bsq { + struct host_bsq_entry host_entry[ QUEUE_SIZE_BS ]; /* host resident buffer supply queue entries */ + int head; /* head of buffer supply queue */ + struct chunk rbd_block; /* array of rbds */ + struct chunk status; /* array of completion status */ + struct buffer* buffer; /* array of rx buffers */ + int free; /* index of first free rx buffer */ + volatile int count; /* count of supplied rx buffers */ +} host_bsq_t; + + +/* header of the firmware image */ + +typedef struct fw_header { + u32 magic; /* magic number */ + u32 version; /* firware version id */ + u32 load_offset; /* fw load offset in board memory */ + u32 start_offset; /* fw execution start address in board memory */ +} fw_header_t; + +#define FW_HEADER_MAGIC 0x65726f66 /* 'fore' */ + + +/* receive buffer supply queues scheme specification */ + +typedef struct bs_spec { + u32 queue_length; /* queue capacity */ + u32 buffer_size; /* host buffer size */ + u32 pool_size; /* number of rbds */ + u32 supply_blksize; /* num of rbds in I/O block (multiple + of 4 between 4 and 124 inclusive) */ +} bs_spec_t; + + +/* initialization command block (one-time command, not in cmd queue) */ + +typedef struct init_block { + enum opcode opcode; /* initialize command */ + enum status status; /* related status word */ + u32 receive_threshold; /* not used */ + u32 num_connect; /* ATM connections */ + u32 cmd_queue_len; /* length of command queue */ + u32 tx_queue_len; /* length of transmit queue */ + u32 rx_queue_len; /* length of receive queue */ + u32 rsd_extension; /* number of extra 32 byte blocks */ + u32 tsd_extension; /* number of extra 32 byte blocks */ + u32 conless_vpvc; /* not used */ + u32 pad[ 2 ]; /* force quad alignment */ + struct bs_spec bs_spec[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues spec */ +} init_block_t; + + +typedef enum media_type { + MEDIA_TYPE_CAT5_UTP = 0x06, /* unshielded twisted pair */ + MEDIA_TYPE_MM_OC3_ST = 0x16, /* multimode fiber ST */ + MEDIA_TYPE_MM_OC3_SC = 0x26, /* multimode fiber SC */ + MEDIA_TYPE_SM_OC3_ST = 0x36, /* single-mode fiber ST */ + MEDIA_TYPE_SM_OC3_SC = 0x46 /* single-mode fiber SC */ +} media_type_t; + +#define FORE200E_MEDIA_INDEX(media_type) ((media_type)>>4) + + +/* cp resident queues */ + +typedef struct cp_queues { + u32 cp_cmdq; /* command queue */ + u32 cp_txq; /* transmit queue */ + u32 cp_rxq; /* receive queue */ + u32 cp_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues */ + u32 imask; /* 1 enables cp to host interrupts */ + u32 istat; /* 1 for interrupt posted */ + u32 heap_base; /* offset form beginning of ram */ + u32 heap_size; /* space available for queues */ + u32 hlogger; /* non zero for host logging */ + u32 heartbeat; /* cp heartbeat */ + u32 fw_release; /* firmware version */ + u32 mon960_release; /* i960 monitor version */ + u32 tq_plen; /* transmit throughput measurements */ + /* make sure the init block remains on a quad word boundary */ + struct init_block init; /* one time cmd, not in cmd queue */ + enum media_type media_type; /* media type id */ + u32 oc3_revision; /* OC-3 revision number */ +} cp_queues_t; + + +/* boot status */ + +typedef enum boot_status { + BSTAT_COLD_START = (u32) 0xc01dc01d, /* cold start */ + BSTAT_SELFTEST_OK = (u32) 0x02201958, /* self-test ok */ + BSTAT_SELFTEST_FAIL = (u32) 0xadbadbad, /* self-test failed */ + BSTAT_CP_RUNNING = (u32) 0xce11feed, /* cp is running */ + BSTAT_MON_TOO_BIG = (u32) 0x10aded00 /* i960 monitor is too big */ +} boot_status_t; + + +/* software UART */ + +typedef struct soft_uart { + u32 send; /* write register */ + u32 recv; /* read register */ +} soft_uart_t; + +#define FORE200E_CP_MONITOR_UART_FREE 0x00000000 +#define FORE200E_CP_MONITOR_UART_AVAIL 0x01000000 + + +/* i960 monitor */ + +typedef struct cp_monitor { + struct soft_uart soft_uart; /* software UART */ + enum boot_status bstat; /* boot status */ + u32 app_base; /* application base offset */ + u32 mon_version; /* i960 monitor version */ +} cp_monitor_t; + + +/* device state */ + +typedef enum fore200e_state { + FORE200E_STATE_BLANK, /* initial state */ + FORE200E_STATE_REGISTER, /* device registered */ + FORE200E_STATE_CONFIGURE, /* bus interface configured */ + FORE200E_STATE_MAP, /* board space mapped in host memory */ + FORE200E_STATE_RESET, /* board resetted */ + FORE200E_STATE_LOAD_FW, /* firmware loaded */ + FORE200E_STATE_START_FW, /* firmware started */ + FORE200E_STATE_INITIALIZE, /* initialize command successful */ + FORE200E_STATE_INIT_CMDQ, /* command queue initialized */ + FORE200E_STATE_INIT_TXQ, /* transmit queue initialized */ + FORE200E_STATE_INIT_RXQ, /* receive queue initialized */ + FORE200E_STATE_INIT_BSQ, /* buffer supply queue initialized */ + FORE200E_STATE_ALLOC_BUF, /* receive buffers allocated */ + FORE200E_STATE_IRQ, /* host interrupt requested */ + FORE200E_STATE_COMPLETE /* initialization completed */ +} fore200e_state; + + +/* PCA-200E registers */ + +typedef struct fore200e_pca_regs { + volatile u32* hcr; /* address of host control register */ + volatile u32* imr; /* address of host interrupt mask register */ + volatile u32* psr; /* address of PCI specific register */ +} fore200e_pca_regs_t; + + +/* SBA-200E registers */ + +typedef struct fore200e_sba_regs { + volatile u32* hcr; /* address of host control register */ + volatile u32* bsr; /* address of burst transfer size register */ + volatile u32* isr; /* address of interrupt level selection register */ +} fore200e_sba_regs_t; + + +/* model-specific registers */ + +typedef union fore200e_regs { + struct fore200e_pca_regs pca; /* PCA-200E registers */ + struct fore200e_sba_regs sba; /* SBA-200E registers */ +} fore200e_regs; + + +struct fore200e; + +/* bus-dependent data */ + +typedef struct fore200e_bus { + char* model_name; /* board model name */ + char* proc_name; /* board name under /proc/atm */ + int descr_alignment; /* tpd/rpd/rbd DMA alignment requirement */ + int buffer_alignment; /* rx buffers DMA alignment requirement */ + int status_alignment; /* status words DMA alignment requirement */ + const unsigned char* fw_data; /* address of firmware data start */ + const unsigned int* fw_size; /* address of firmware data size */ + u32 (*read)(volatile u32*); + void (*write)(u32, volatile u32*); + u32 (*dma_map)(struct fore200e*, void*, int); + void (*dma_unmap)(struct fore200e*, u32, int); + void (*dma_sync)(struct fore200e*, u32, int); + int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int); + void (*dma_chunk_free)(struct fore200e*, struct chunk*); + struct fore200e* (*detect)(const struct fore200e_bus*, int); + int (*configure)(struct fore200e*); + int (*map)(struct fore200e*); + void (*reset)(struct fore200e*); + int (*prom_read)(struct fore200e*, struct prom_data*); + void (*unmap)(struct fore200e*); + void (*irq_enable)(struct fore200e*); + int (*irq_check)(struct fore200e*); + void (*irq_ack)(struct fore200e*); + int (*proc_read)(struct fore200e*, char*); +} fore200e_bus_t; + + +/* per-device data */ + +typedef struct fore200e { + struct fore200e* next; /* next device */ + const struct fore200e_bus* bus; /* bus-dependent code and data */ + union fore200e_regs regs; /* bus-dependent registers */ + struct atm_dev* atm_dev; /* ATM device */ + + enum fore200e_state state; /* device state */ + + char name[16]; /* device name */ + void* bus_dev; /* bus-specific kernel data */ + int irq; /* irq number */ + unsigned long phys_base; /* physical base address */ + void* virt_base; /* virtual base address */ + + unsigned char esi[ ESI_LEN ]; /* end system identifier */ + + struct cp_monitor* cp_monitor; /* i960 monitor address */ + struct cp_queues* cp_queues; /* cp resident queues */ + struct host_cmdq host_cmdq; /* host resident cmd queue */ + struct host_txq host_txq; /* host resident tx queue */ + struct host_rxq host_rxq; /* host resident rx queue */ + /* host resident buffer supply queues */ + struct host_bsq host_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; + + u32 available_cell_rate; /* remaining pseudo-CBR bw on link */ + + int loop_mode; /* S/UNI loopback mode */ + + struct stats* stats; /* last snapshot of the stats */ + + struct semaphore rate_sf; /* protects rate reservation ops */ + spinlock_t tx_lock; /* protects tx ops */ + +} fore200e_t; + + +/* per-vcc data */ + +typedef struct fore200e_vcc { + enum buffer_scheme scheme; /* rx buffer scheme */ + struct tpd_rate rate; /* tx rate control data */ + int rx_min_pdu; /* size of smallest PDU received */ + int rx_max_pdu; /* size of largest PDU received */ + int tx_min_pdu; /* size of smallest PDU transmitted */ + int tx_max_pdu; /* size of largest PDU transmitted */ +} fore200e_vcc_t; + + + +/* 200E-series common memory layout */ + +#define FORE200E_CP_MONITOR_OFFSET 0x00000400 /* i960 monitor interface */ +#define FORE200E_CP_QUEUES_OFFSET 0x00004d40 /* cp resident queues */ + + +/* PCA-200E memory layout */ + +#define PCA200E_IOSPACE_LENGTH 0x00200000 + +#define PCA200E_HCR_OFFSET 0x00100000 /* board control register */ +#define PCA200E_IMR_OFFSET 0x00100004 /* host IRQ mask register */ +#define PCA200E_PSR_OFFSET 0x00100008 /* PCI specific register */ + + +/* PCA-200E host control register */ + +#define PCA200E_HCR_RESET (1<<0) /* read / write */ +#define PCA200E_HCR_HOLD_LOCK (1<<1) /* read / write */ +#define PCA200E_HCR_I960FAIL (1<<2) /* read */ +#define PCA200E_HCR_INTRB (1<<2) /* write */ +#define PCA200E_HCR_HOLD_ACK (1<<3) /* read */ +#define PCA200E_HCR_INTRA (1<<3) /* write */ +#define PCA200E_HCR_OUTFULL (1<<4) /* read */ +#define PCA200E_HCR_CLRINTR (1<<4) /* write */ +#define PCA200E_HCR_ESPHOLD (1<<5) /* read */ +#define PCA200E_HCR_INFULL (1<<6) /* read */ +#define PCA200E_HCR_TESTMODE (1<<7) /* read */ + + +/* PCA-200E PCI bus interface regs (offsets in PCI config space) */ + +#define PCA200E_PCI_LATENCY 0x40 /* maximum slave latenty */ +#define PCA200E_PCI_MASTER_CTRL 0x41 /* master control */ +#define PCA200E_PCI_THRESHOLD 0x42 /* burst / continous req threshold */ + +/* PBI master control register */ + +#define PCA200E_CTRL_DIS_CACHE_RD (1<<0) /* disable cache-line reads */ +#define PCA200E_CTRL_DIS_WRT_INVAL (1<<1) /* disable writes and invalidates */ +#define PCA200E_CTRL_2_CACHE_WRT_INVAL (1<<2) /* require 2 cache-lines for writes and invalidates */ +#define PCA200E_CTRL_IGN_LAT_TIMER (1<<3) /* ignore the latency timer */ +#define PCA200E_CTRL_ENA_CONT_REQ_MODE (1<<4) /* enable continuous request mode */ +#define PCA200E_CTRL_LARGE_PCI_BURSTS (1<<5) /* force large PCI bus bursts */ +#define PCA200E_CTRL_CONVERT_ENDIAN (1<<6) /* convert endianess of slave RAM accesses */ + + + +#define SBA200E_PROM_NAME "FORE,sba-200e" /* device name in openprom tree */ + + +/* size of SBA-200E registers */ + +#define SBA200E_HCR_LENGTH 4 +#define SBA200E_BSR_LENGTH 4 +#define SBA200E_ISR_LENGTH 4 +#define SBA200E_RAM_LENGTH 0x40000 + + +/* SBA-200E SBUS burst transfer size register */ + +#define SBA200E_BSR_BURST4 0x04 +#define SBA200E_BSR_BURST8 0x08 +#define SBA200E_BSR_BURST16 0x10 + + +/* SBA-200E host control register */ + +#define SBA200E_HCR_RESET (1<<0) /* read / write (sticky) */ +#define SBA200E_HCR_HOLD_LOCK (1<<1) /* read / write (sticky) */ +#define SBA200E_HCR_I960FAIL (1<<2) /* read */ +#define SBA200E_HCR_I960SETINTR (1<<2) /* write */ +#define SBA200E_HCR_OUTFULL (1<<3) /* read */ +#define SBA200E_HCR_INTR_CLR (1<<3) /* write */ +#define SBA200E_HCR_INTR_ENA (1<<4) /* read / write (sticky) */ +#define SBA200E_HCR_ESPHOLD (1<<5) /* read */ +#define SBA200E_HCR_INFULL (1<<6) /* read */ +#define SBA200E_HCR_TESTMODE (1<<7) /* read */ +#define SBA200E_HCR_INTR_REQ (1<<8) /* read */ + +#define SBA200E_HCR_STICKY (SBA200E_HCR_RESET | SBA200E_HCR_HOLD_LOCK | SBA200E_HCR_INTR_ENA) + + +#endif /* __KERNEL__ */ +#endif /* _FORE200E_H */ diff -u --recursive --new-file v2.3.47/linux/drivers/atm/fore200e_firmware_copyright linux/drivers/atm/fore200e_firmware_copyright --- v2.3.47/linux/drivers/atm/fore200e_firmware_copyright Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/fore200e_firmware_copyright Mon Feb 21 16:32:27 2000 @@ -0,0 +1,31 @@ + +These microcode data are placed under the terms of the GNU General Public License. + +We would prefer you not to distribute modified versions of it and not to ask +for assembly or other microcode source. + +Copyright (c) 1995-2000 FORE Systems, Inc., as an unpublished work. This +notice does not imply unrestricted or public access to these materials which +are a trade secret of FORE Systems, Inc. or its subsidiaries or affiliates +(together referred to as "FORE"), and which may not be reproduced, used, sold +or transferred to any third party without FORE's prior written consent. All +rights reserved. + +U.S. Government Restricted Rights. If you are licensing the Software on +behalf of the U.S. Government ("Government"), the following provisions apply +to you. If the software is supplied to the Department of Defense ("DoD"), it +is classified as "Commercial Computer Software" under paragraph 252.227-7014 +of the DoD Supplement to the Federal Acquisition Regulations ("DFARS") (or any +successor regulations) and the Government is acquiring only the license +rights granted herein (the license rights customarily provided to non-Government +users). If the Software is supplied to any unit or agency of the Government +other than the DoD, it is classified as "Restricted Computer Software" and +the Government's rights in the Software are defined in paragraph 52.227-19 of +the Federal Acquisition Regulations ("FAR") (or any successor regulations) or, +in the cases of NASA, in paragraph 18.52.227-86 of the NASA Supplement to the FAR +(or any successor regulations). + +FORE Systems is a registered trademark, and ForeRunner, ForeRunnerLE, and +ForeThought are trademarks of FORE Systems, Inc. All other brands or product +names are trademarks or registered trademarks of their respective holders. + diff -u --recursive --new-file v2.3.47/linux/drivers/atm/fore200e_mkfirm.c linux/drivers/atm/fore200e_mkfirm.c --- v2.3.47/linux/drivers/atm/fore200e_mkfirm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/fore200e_mkfirm.c Mon Feb 21 16:32:27 2000 @@ -0,0 +1,155 @@ +/* + $Id: fore200e_mkfirm.c,v 1.1 2000/02/21 16:04:32 davem Exp $ + + mkfirm.c: generates a C readable file from a binary firmware image + + Christophe Lizzi (lizzi@{csti.fr, cnam.fr}), June 1999. + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. +*/ + +#include +#include +#include + +char* default_basename = "pca200e"; /* was initially written for the PCA-200E firmware */ +char* default_infname = ""; +char* default_outfname = ""; + +char* progname; +int verbose = 0; +int inkernel = 0; + + +void usage(void) +{ + fprintf(stderr, + "%s: [-v] [-k] [-b basename ] [-i firmware.bin] [-o firmware.c]\n", + progname); + exit(-1); +} + + +int main(int argc, char** argv) +{ + time_t now; + char* infname = NULL; + char* outfname = NULL; + char* basename = NULL; + FILE* infile; + FILE* outfile; + unsigned firmsize; + int c; + + progname = *(argv++); + + while (argc > 1) { + if ((*argv)[0] == '-') { + switch ((*argv)[1]) { + case 'i': + if (argc-- < 3) + usage(); + infname = *(++argv); + break; + case 'o': + if (argc-- < 3) + usage(); + outfname = *(++argv); + break; + case 'b': + if (argc-- < 3) + usage(); + basename = *(++argv); + break; + case 'v': + verbose = 1; + break; + case 'k': + inkernel = 1; + break; + default: + usage(); + } + } + else { + usage(); + } + argc--; + argv++; + } + + if (infname != NULL) { + infile = fopen(infname, "r"); + if (infile == NULL) { + fprintf(stderr, "%s: can't open %s for reading\n", + progname, infname); + exit(-2); + } + } + else { + infile = stdin; + infname = default_infname; + } + + if (outfname) { + outfile = fopen(outfname, "w"); + if (outfile == NULL) { + fprintf(stderr, "%s: can't open %s for writing\n", + progname, outfname); + exit(-3); + } + } + else { + outfile = stdout; + outfname = default_outfname; + } + + if (basename == NULL) + basename = default_basename; + + if (verbose) { + fprintf(stderr, "%s: input file = %s\n", progname, infname ); + fprintf(stderr, "%s: output file = %s\n", progname, outfname ); + fprintf(stderr, "%s: firmware basename = %s\n", progname, basename ); + } + + time(&now); + fprintf(outfile, "/*\n generated by %s from %s on %s" + " DO NOT EDIT!\n*/\n\n", + progname, infname, ctime(&now)); + + if (inkernel) + fprintf(outfile, "#include \n\n" ); + + /* XXX force 32 bit alignment? */ + fprintf(outfile, "const unsigned char%s %s_data[] = {\n", + inkernel ? " __initdata" : "", basename ); + + c = getc(infile); + fprintf(outfile,"\t0x%02x", c); + firmsize = 1; + + while ((c = getc(infile)) >= 0) { + + if (firmsize++ % 8) + fprintf(outfile,", 0x%02x", c); + else + fprintf(outfile,",\n\t0x%02x", c); + } + + fprintf(outfile, "\n};\n\n"); + + fprintf(outfile, "const unsigned int%s %s_size = %u;\n", + inkernel ? " __initdata" : "", basename, firmsize ); + + if (infile != stdin) + fclose(infile); + if (outfile != stdout) + fclose(outfile); + + if(verbose) + fprintf(stderr, "%s: firmware size = %u\n", progname, firmsize); + + exit(0); +} diff -u --recursive --new-file v2.3.47/linux/drivers/atm/iphase.c linux/drivers/atm/iphase.c --- v2.3.47/linux/drivers/atm/iphase.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/iphase.c Mon Feb 21 16:32:27 2000 @@ -2359,7 +2359,7 @@ { printk(DEV_LABEL "(itf %d): can't enable memory (0x%x)\n", dev->number,error); - return error; + return -EIO; } /* * Delay at least 1us before doing any mem accesses (how 'bout 10?) @@ -2499,7 +2499,7 @@ printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" "master (0x%x)\n",dev->number, error); free_irq(iadev->irq, dev); - return error; + return -EIO; } udelay(10); @@ -3074,7 +3074,7 @@ { if (!skb) printk(KERN_CRIT "null skb in ia_send\n"); - dev_kfree_skb(skb); + else dev_kfree_skb(skb); return -EINVAL; } spin_lock_irqsave(&iadev->tx_lock, flags); diff -u --recursive --new-file v2.3.47/linux/drivers/atm/pca200e.data linux/drivers/atm/pca200e.data --- v2.3.47/linux/drivers/atm/pca200e.data Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/pca200e.data Mon Feb 21 16:32:27 2000 @@ -0,0 +1,850 @@ +:150000001F8B0808AB5A10380203706361323030652E62696E4D +:150015007D00E43A0D7014D7796FA5BDE84EC86211A7333020EE +:15002A00AD89C00A23EA83AA589C7E7C38D8152EB887477677D3 +:15003F0095C39C3DB2AB388CA324C4A509352BFBB085BBD0C73F +:150054007210B903C92991CCD1B1C242255BCCD81EA5C34C6826 +:1500690006271AC6D36A3A31B976D4A9A683DB4B07BB38265C56 +:15007E00BFEFBDB7777BA7030B2733994C35737AFBBEF7BDEFE7 +:15009300EF7DDFF7BEF7769FFEEAD79F221221E1ED844C3E4677 +:1500A8007EA3BFF036F827CF8597C3AF0C7E920B16595BCE5AA8 +:1500BD00296B6483D83E9F7DBE8FF50BE74A0B45FB1F274FAA79 +:1500D200D82E2867139DF637FD937EF1D55FB0769FE8678BDAFB +:1500E7007D9BD8885451515172FE27E4138E9FC9949CBFF026BC +:1500FC00741DF83ECE59823FF23BF89346493F6B4F17C1B3A7CE +:15011100B3B79C97D3275B5ABFEC3CF9579457703B3CBFEFD600 +:15012600FC38236CA91B5E347EDBFA67F7ED4397956EA4D3C5F4 +:15013B007CE6A567799EFFF5CFC4FF7BDF938BF83E83EDE59F02 +:15015000FEAC24BF8A3C3F2FF9FDFF933CF51EF2FFEC2FEBFA11 +:150165002341C38CBC5F4EAA265F5EAF04BC51F0059FD1419ED8 +:15017A00063493D465A2384E66A0171C30231F40AB5CB5646FC8 +:15018F005CBFB633DECCC614D2DAF622F15D3189EFEA3EE28B83 +:1501A4007D99F8DABE4D7C2418A438AF3129015D7507F1032EBA +:1501B900E174827F46C82229AE2BC63A9D50E9253960EC005FCA +:1501CE00F2EDFE0AF12A9D5EBD6A35F1B5AC441A49BAD94F22C6 +:1501E300DECB544F180D1A51FACD8C4A7C034B93DAFD6455A8F9 +:1501F8009AAC5AB74C9542EF11E23DB0946A0F1B0DA10BF0CC0C +:15020D00F9A4A8097BCA1D751474A02FEC02593C75C9E870D176 +:15022200B8CF352EC3783C379E1C2893C98017C6A57B3CDD0E4D +:15023700CE32426A9CB99F03FC2E81BF46AD0D06544FD0190B08 +:15024C00C0580B8E897EFDF490DE08FD652E9CFAE911DD5F24FE +:15026100CF832469DAB1116BE0F3C437B686F8D275C437AC9220 +:150276000542BFF6CC0320B22AB7237E1F5B97A4E927A397490C +:15028B0064C43AFF0CD8ACCE8886D37F632A7F4C16005E289CAF +:1502A0003E491DDAFB083513C6B0A6B8E4929626F531E0877479 +:1502B50082E58C9E2503DDD45DC4777E3BF1051F253E09684E42 +:1502CA00C3BAC26825AC39F5225F6598EE23B366227C52ABFC3A +:1502DF00BC2754E61BD1FFEBAE6DCDFE8D49AAEA38EE89A35A1B +:1502F4009DF0DCF4254234681BBB09E98536033F2F3C5F835F24 +:15030900107E147E1AE8AA0406A36989DB63C95ADE9F9272EBA7 +:15031E00C17C6131AC4519193457028723BE118D0433D6F063E5 +:150333005C6E1C77EC2981FD118663B2FA3A455F8D11A2D66BC0 +:15034800AFE9B096E6D4A38454D70D004ECA8235541117C7A5F2 +:15035D002D26F8E4B07D3848BA956402FC7BF8EC956CB6B6D35F +:1503720091EB21B280C218CAB04122B5957583D126189B7D88FF +:15038700FB2BDA46560F52056C867C6CE85FF1135F19E0C948D1 +:15039C0023873342916798F3A6E45FA58C9021887DB9A8DF9307 +:1503B1002EECF7421F693AB054DE6F73F4FDF414E83A6B66B2C0 +:1503C6000B11C3BA0E45D0D1074E3318C92C24FE074FF267E847 +:1503DB00E03AE67193D635C40D9FD66A65B471CABA5AC66D9C17 +:1503F00081B68DE4F5200AEA316B3E3EF5F8D4CAF0C902BFBC6E +:1504050003FD12ED00BE39F8E7C4E765F2A6F8BCC8083DA6B648 +:15041A00335DAAA0AFC4DEA66A6CDC8418EA26910FAD6A0821BE +:15042F0012B4A9C269D1DDAC9DB05A98BD06B91D807702D6021B +:15044400F02CA479BF88CD3D82BE3F92D49137C262E0EB5969BB +:15045900D6AC8DA4F4A3A0EB808FEB8570E6F34897F9F77CE4C2 +:15046E0071E4E07C73F2C0FC256AC3208B2D5C834D43BA3F060F +:15048300F39566B386103FC611E321E23D02F1168A79426C3DFD +:15049800E159DA32AAA34C083FBA62DC2474847A94BF031D86A2 +:1504AD00ACE5EAEB969CDC4FF3F3216F03DE5414FD8ED3DA3050 +:1504C2005F5AC953795A804F2146D05612811C0DB6A0BC0E67DE +:1504D7007C6E471FC3A5CFA04B06639EFA201E11FA182E7D3E53 +:1504EC009556913E89227D129F511FDBA5CF05970CF63CF54199 +:15050100BCE097B83EB64B9F4FA555A4CF60913E839F511F752A +:1505160026AF4FCB4C5E0684CF471FC48B75737DF079C37C69B3 +:15052B0015E973BC489FE32E7DC231AFD997FEF15925301975DC +:150540007CBC5E33F5D918F2E53E82FD69D1B745FF82E8237F22 +:15055500EC4FB07ED2A4626FD8C3F7363321FA29D11F14FD6938 +:15056A00D13F2EFA9D40678FFA1ACBD131181B507F88FBA8451E +:15057F00E179507D8362EC4FC2734A7D8786D5D526CF431356CC +:1505940010E6D51152BB2CE6690F243DED35694FBB17D6017487 +:1505A900B251C766F514A3D3037337AB67189D043C77A9E728AB +:1505BE00CE3FCFE5A0C8B347ED17F9CDB09A812EE4A09AFBC861 +:1505D30005F3ECCE1F76B0B8059C6AD51342D87777BEC16093F7 +:1505E8002ED82B3BDF613094C9813DB7F3A50E87FE6A95AF1F58 +:1505FD00D259C69E53B447F047991EAA1FDDE8D0747091968332 +:15061200EBC88AB2D5095CA4FB07AA87ED030961D37494DB348F +:15062700C27225D77D497EBF32958271CE6F8DA0D12CF612E37F +:15063C00718ED32568206F3FDF874C7B477EAC4DD8310AE35B40 +:15065100C17E683B139EA3EA6178A6D65B4CA65926E72EF555F4 +:150666007A82D977D06A9A610E58F3D80D4F6BFDF4DDFAC37506 +:15067B00E7D67D672AA93DD881720C301B55C6E4D0860EB97506 +:150690007D5DFF3A0A636BD898CDE4AD4C7A42CBDE915B037587 +:1506A50087D7593056DDC1E5477B55429CDCF8B5DCFAAB15AFBD +:1506BA00AE3B0263FFD3EE69AF8C5584FEF3FD0FDA90E6BFADE7 +:1506CF0030DB70FEBF9C186B43DC4BEFBFDE4682BD8C27C86F5A +:1506E400B3BC185CC264063DED086BF730DA2418B655D6F63110 +:1506F900394850B53126EEFCD1AC2EBD1B83F83B6D56056C5662 +:15070E0027F079B3565739DFC3A2AC8D591AB48B37FD4097B6BD +:150723007D4527CA41F38E00D6C48665887A30CEDA5E6BA09CE8 +:15073800EF7568CF8A7EC03FF80DC05F6B56078280AFB25C86D9 +:15074D00F863ACEDB32658DBC26CBEE04780FFEEB7017F9BB98C +:15076200301001FCB0C5E54E5A0DD0BEC8D6618FD53893DFDBC0 +:15077700489D0A781A5B9B27616DFAD4435409C08E179C365B01 +:15078C00B86D2C5EB34E5BCDD0CEC0B98106CBBA25A29A87AEC7 +:1507A100676BD0977601BC4A7DCDC2BA15ED575E1DD7B78610CF +:1507B6008FC715EE954F0A5CB4B78837139F9F079E8AEFA21E32 +:1507CB00DF9814679714AB9163E99F59FEBDE3263A704FFA4DF8 +:1507E0000BFAD400D9FCE1115DF1C541C7772D591DB7BA1C7929 +:1507F500D4BBCC1B9F701EC761BE22E4A1429EB736E6E5C1BDA9 +:15080A00EE92C09D74C933790B79222E79BA401EE8535A429E39 +:15081F00F3ABF2F23C2B785CC43812F24C0A799A5CF2E05E759D +:15083400BFC0457F73E4C1E79BC91376C9B319E4813E4D9690D5 +:15084900A7D925CFE55F711E6D33B8A771799007CA73BC252F86 +:15085E000FEE3567392EE35506B935DE3E625D87B3AC9363DDC5 +:15087300675D387B325FEEC53DCA370CF1D064D2707F1F9E1BAD +:15088800BCCC7732962CFCB60AF76B17AFD80C1694A4D6EBDAB7 +:15089D0047E58DFC1CEB75E1E10563311E21B6794C95704FA00C +:1508B20031EEBF8BC93DD0270326EC0F8A54674771FCCEF0B040 +:1508C7007E67F81CD864D8EA401CC819480FE1811DBC76E5FDFE +:1508DC00733A83FDD508D6AA24406D9DCF3FA75FCC66FD65D592 +:1508F100FDFAEE7BF332F5F0FDC225936D769033AD01550A3A24 +:15090600BCF12CBF86F184F305E007567C68E59EDB3FCCF1498D +:15091B00D79F692B73E8803CC25E4CAEDA152370463A4A2DE42F +:15093000AB34998BC0DE1BD01C0AA7C5715314ED0FC74F4B510E +:150945005ED2BDC9319893001F18B3A2AE734B17D4E2CFA89EB1 +:15095A00D6B7245E6394E2F350520E95A6DD6079943780F65B70 +:15096F00507B1C857AE36D0B6B12491D8133EA88E6D41A72B92A +:15098400A835607E52D421448C255D7548EE0F723FD656E84744 +:15099900CA3D28974DE33C4751AF90CFEB9603D61BE545BA8197 +:1509AE00906D2A44D446CA190BE550DE5F85B273DF637264CCC1 +:1509C300C15E487501388B928C8974B4ED9C4E8FD80F395D9B32 +:1509D800D9A7F6FDFD5482B3B6141B358F92514D3A30CEEA2EE8 +:1509ED003EC7B6108744E478BE6ECB98555F46FA54D0E77A23D8 +:150A0200FDE876AE1FE7932AE0C3EC226CC2EC98E676BC7347DE +:150A1700DC0A446C361675F3A48267306C72595A4C85D9A5D310 +:150A2C006467AB60D0E4761AA00C1E19A6CFDE057584F27DAC4C +:150A4100810A64F09F5845DD6B073896ACC05936324E1D3FC1D0 +:150A56001C843796C7485C2391FD168998CC2EAC0E807119F419 +:150A6B00A52D86899716E555719D1E5CABF77860FDA686D87D2E +:150A8000881FD74839ABCBEADB34C06AE6FC196F49F9DC3367A7 +:150A9500FF9653FCBCE83E774E9DC198FD9433E7203F734E0EF2 +:150AAA00E7CE9BECEC19F9BEE5F8961C30A2634DFCFEA0D0B70D +:150ABF00B82FA14CBDC23E6C6D4249E6574419B2081DA247F1E2 +:150AD400AE02FC0A7D81D9CC00FA74C84ADCC82E72F9336B3524 +:150AE90075186487D8A757CCC5B06FE37D56B5BAAAF912D674D6 +:150AFE0012F13EA3AE0D5D83985C9FF6B7B3DAEE31CEB713DA06 +:150B130045E420F33B90DB12700BE117C47D4058E0468A700568 +:150B2800DC42F87111EF0EFD1E316777D11C01B710DE2BE8F75C +:150B3D000A5CA30857C02D84B709FA2B05FD06818B78F8BCDCC9 +:150B5200956F1A5D63F88C67293C4379C18FCAAB46C037862CF0 +:150B6700B497ACBCA2E37A07D5613B00F6AA091FED901553AFF3 +:150B7C00EDBFA257A9A7AC65C6076D814DFFADCBB131EB44D2FC +:150B9100D3ED8D9966269B5D0C355EAB1CBB62393E5B09B92DA1 +:150BA6007D3DEB73C7C0B7A0CE95599D4AE7C4A388AF5C5E4121 +:150BBB001ACAA1213D513EACA16C353B1A2C279ED9DA634E30EB +:150BD0002027A4DFC63C22E273C22A8E67F405C61362C61D27AE +:150BE5002FDE11D7C365DC0F1591D33E2D4E5E82FD3B17230768 +:150BFA008634CC078AD84F31565642CAC2B3E0D3AC9E17310500 +:150C0F00F1F318F89BA8DF73B0FBC5B9E2E6B1D4226269A8F448 +:150C2400FD8D2B9E7ABEF0DBCFD57473E2296C3D2DEC7EBCF2E1 +:150C3900AE00DF13950DDEA802CFB7FA713CC25A35E0ECA52AC3 +:150C4E00D412F544A96ED2E3655F78CA23E0B4C678CA19C73BC6 +:150C63007A25DCF084ECD008279EA8719E37E5E1B9FD8ADDB182 +:150C78000DC0764CD423AADC4D73B519BFDF7C84EDF7B3589BA5 +:150C8D002978178F2324729206D4F666ACDF181C6C7FFDBEF62F +:150CA2003F04FFB4091D3E8BEDE2C8A08EF7A1481361354A427E +:150CB700BF0075C79CFD52F0EFBA09FFF58CFF80C9F2281DB6EB +:150CCC00918E943ECEE946809780E173BA047D6A637DC3E9E326 +:150CE100FD30D41426ABD5A0BF066353F5B7AD57AB426111E732 +:150CF6002175793BD0A435CA01DD9101E36E51513FF72CF85916 +:150D0B00533FD0D6AB0F846AD4079A03EAAAD056276FA94F71C2 +:150D2000DA82A6E43B3E87AEF48FB786AD4E2F6F75EEA36584E2 +:150D3500837D8F64208743DE10F7CD8B56A7E5565C0F7627CD82 +:150D4A0071E811C84132E2404C200ECA9A85BA8E1AFB35425244 +:150D5F00980BCDECDF9F97C1AF71CF55D02E2C2EA660BF823D2D +:150D74006135190E61FC6476BEDEE1BEA7FD9C787F107F84E908 +:150D89005860EF2C9930495D2A9AA76D08DAB6C1624F81FD644F +:150D9E0072445B638C94A45D2168373E42BCEE7D285F5F65CC2D +:150DB300E4D7B03E3172F5C9FCF381CDF301E856321F28AE3A51 +:150DC80028771E688C4A5BD641CD07B107B58A72379C210E6DFD +:150DDD00D477415EF648712D0AAD1C4846132A3F977C1772DDE5 +:150DF200B1E4C7CDE4EA10BDF6B5FC7B8D3D5FFFDDFEA623C476 +:150E070037F149D60767196DF37D72BB73D787F76764B77176CD +:150E1C0012DFEDED4E9E9D62ED24C612B4E9B319F6CE0FCEC553 +:150E310060A795E28EC5592B49ACD55EA03DFBA77C1F408D2F19 +:150E4600C19925111ED61AB1FD22D431CC768DCC76686BC46913 +:150E5B00025948755C5BFE89B05F4C62F603E3079A805E15C03F +:150E70007F7E9F7C2F5BCFEDA2BE82166B17AC59900EF6BB59E8 +:150E85003D95F781473ED50706C49DFE70491F5072FB7DC6422E +:150E9A009DC136B6B08D2D6C630BDBD8689B72C8E56E9F99AF8B +:150EAF003DF1DD13D451C14A757F10CEF8BE3C6C2DC00E06535C +:150EC40005B03F02D8D1E09803AB42582DC056042711C6EE3D4A +:150ED900B87DDFFB18EC09763DFFF15CBBBEF730F18D7D8C764C +:150EEE006DB877BE7ACD579F7809FF2813FE1105BE17B615CA1F +:150F0300D922135F23C8E20159979490B511E67899AC4DF7DEFF +:150F1800CE1ACC57DEDE12F2960B795F0759976C9BEBCF06FAC8 +:150F2D004B095F8E5DCBFACA408FC8B5B97AC4804EF81AEAE194 +:150F4200BFF7767DE976F4E929A18F2CF4F9F956E2EB84DF675D +:150F5700E1BFF97F4127B5812A6A1365EFE620074AB029B701EC +:150F6C001CFB32E934357C0E6AA60AD659AEEA96A26EFA5B76F9 +:150F8100970E79676B6C88BD2B8E7D53DCF73CC76A5433FD0D60 +:150F9600A89D643847E33B55DC9401EF62EC9455F5C419EBC295 +:150FAB00479C3601BAD9858639057D89F7BD631F15CA33267057 +:150FC000DF83B68B244DBFCAF9118DF3433EC8CFDE5DC86F3932 +:150FD500E0553D71CADA0AFC3441837EC4F9C5043FE87BDDF609 +:150FEA0054843DCD3FE1EFB8AF3E440AC61789F15D62FCBDA29D +:150FFF00F11A31BE558C8F158D2F16E34D623CC1C63366D79E29 +:15101400FC793F0B3A5202FB37ECD5DEE52452707687BF81A5FC +:15102900B646E14C41EA923BF0AC5963EC5F87EFF53591D70ED8 +:15103E002C9DD53AC22F873A5DF7E92F4C3CF113B4D573BB2F35 +:1510530075045DF0CBAFFEF57584B7EEF84987FBFE7DFA8D6F83 +:151068009D40F893FFF0E30EC2BE871834E3FFFC179BFC0163E8 +:15107D0047B297F8269F24BE3972BAEE17827F59B87FCB380E23 +:15109200F9167388548D39197231C24AECC74EAE81B351FBEE40 +:1510A7002DE2DE07700F6C19D52A638F065F811671F66EE7672C +:1510BC003C1C73CE320C5644AF8EDFF7F1EF332E0FE8F683F8F2 +:1510D1001D01FB1640C47E8ADD2918BE51B6571056CB2419BE69 +:1510E6005F39CDEE52768B7B1784A9EA283B4BED71C18202D67F +:1510FB00E7823509D8DE99FCB707866B1CED4B26086954472D8C +:15111000370CBF436C2882554932692E84518A67BFD838550E10 +:151125008DEA2D3826F4C6EF6508BD9BD99D8AF91FDC58F453B2 +:15113A002F9B9FF345D18A7E649C4A07F09C0338ECFD3DE713EE +:15114F005647E93EA827B19EC2F3EE65F0B7441FE9C6F74ED3D0 +:15116400397FE1B66DACE2760DA74FE6E40CA74FD3FE2DE3DA2C +:151179006675DC72D37C79E98086FB33D28C15ECEFA3ECEE6226 +:15118E00AB80ED1132EE113206605F6732E27B2576864DE1DED8 +:1511A300CF6A05B6F78BB51C106B298B6F2998CDA06605DE16C5 +:1511B8007EFF9280338317CFA17866127A7845AB14B5176F64D1 +:1511CD000BEA546EDF93EC5E0EF76903F4C3332E3E3B30F2F086 +:1511E2005C58991BC6EAE794D509272B493C6F56381C6C66A124 +:1511F700DD6A33CCCE0143C8C160013B1AD89812E727389FC223 +:15120C009C5A03D60DD688B591717321D2A3A356297C52029F42 +:15122100E4F0DFE4F605183C5B7B9DCFF944FCBD20F4E4B19C55 +:1512360062758BE4E804CF57A514F3F7A03F3FFEF296FCB8034D +:15124B007BA9044C7E782ECCE386B9623AE7DF22A69C7875C78E +:15126000727F512C633B25C66E36C72831C7196BC4F68BF9B97C +:151275009590BB8DBBC902278FA04D5E747C0E9EEBA7E37AAC39 +:15128A00687CC1E594CE69A4CC1648B68998A71B7CAC06F7016D +:15129F0073733E27A17F605C38637DEE31F6ED1BA7C35A178D76 +:1512B400CE221A8E0DB80F7298510C037A2F38307F1E66948027 +:1512C900555617C250A7FD2E9D1D58BC04ACBCDA0D334CBB4EC1 +:1512DE0026E1D5C23EB08F60CEC0B8F483CF634D85DFE4B17ECD +:1512F3002015AD75BD4B225584BD3342FFF533FF1D311D3FAFDB +:151308003C84DF1BD87400BFB50BF35C568A8672DB34600CF7B2 +:15131D00176514F12C2D1717498AF91CF3E12ECC25D0C77907C1 +:1513320097A634461F7DC54F6829B8E2829B6EFC25A5E10AC018 +:151347007B9DEFDEEA788E75DB6BAB74137BF94BEBBAE0B20DCC +:15135C0067E4D1BE83504BB03C301FBBFD1669A19EB75A03F3CC +:1513710076E4FACCB40AD7D51679DED9AB793E2EB475613E2E11 +:15138600210BCCE1B2A44CD602ED85480F6ABE927628814F729C +:15139B00F885F2ED75F91DC6AF543D37BE49F5DCF82EAB9E1BB7 +:1513B000CBA404EC15DFDCF8F654CF8D65B90886F847DC73F32E +:1513C500EF3C2B79FD8531CEF706B469BD6BEF83D6D825BEDF9F +:1513DA0020AEBD50291A935D63FEA231AF6B6C49D158956B6C58 +:1513EF00B922F611E52D4A1493CAEA307BCFC4BF63A4F41A6BD3 +:1514040007E9F532BEE765581B34A1A82072F5889E30C635FCEE +:151419005676B13CA21F2B1FD78E854735AC55BE639CD3BC1730 +:15142E003FD0192E201F360E68CA5653AF81BC5CE97AFF8BDFE1 +:151443008FCAE638833F17AB0ACDB8D613DFFBFFD37DFC7B9AE7 +:1514580058EEDB1B80CFF0335F65F2D7CDCB92DFC4EF4EC4B7BF +:15146D003313ECBB277E5F3EC1BF8D080E50FEBD0C1538830C25 +:15148200A7D7F57E03DF9F3F2BF84CCEE17347011FFE7DCD0460 +:15149700FB7ECAE1630B3E5D820FC719345551A725A13D119479 +:1514AC00BA2B0E8DE8FEF02AFD353C9FC4EE6E0BC42A425745A7 +:1514C1007C5D8ADD139A85672FD8BF5E8BEBD433DA5719F3B4AB +:1514D600E33A292ABE8B033BBE097935297577A9A72C388AD66C +:1514EB00C8CA5A88EB03B42E7CB0ED30665CA5DFC46F5D37FF53 +:151500003B9CEB22BFB41AD45F5ACEFBE836F58015560F5BFEA9 +:15151500F408FDBFF6BE3E3A8AEBCAF355AB5A6A498DA816ADA6 +:15152A0046C2209588708447715A422648964C43182F78306934 +:15153F00639CAD12C26EDB644C1C26A3DD61E7704E58BB255AC4 +:1515540020E10729D548462638B4B064E30938322B123C47248E +:1515690062E275F02C61B48CC390C4269D19C626332456BC4A65 +:15157E0086CD38F4DEDFABAAEE9210FE9839B367FF58D5D1A9A8 +:15159300EA57EFE3BE7BEFBBEFDEF7EEBB657887B6D5087BF17D +:1515A800081FA63A83A941B22B5F3491CE945E0EDF6E779BEBA1 +:1515BD00BF3ED0EC2E5FA1FD996EDA75A02C9E5157FCDBF00DF9 +:1515D200AF6E8D4C2B5F4CE523EA336693FA8A5DBE77C6F2D17B +:1515E700E31818D5AD80254CEF6AD47623AC7673ACFB9A2CD1D0 +:1515FC00A6A93F37BD12FC228E7293F5B5C9B184594CF2CC8307 +:151611007DE9E8A0E98BF59AFED8A869EDDBB8F9F8A4CDC7F152 +:15162600297C9CE1DFB1214D71F16F51CCDB98E151EC1B61AFE5 +:15163B008478348FE466095BA45B7DABB6FA16196876F3735093 +:15165000ED364231F94E6BBFC1E0F0E51DF97BAC8FC45BA1DF9D +:15166500AF6E60F987CA929AA22E16B459053AC0F5491D31629D +:15167A00EA5123A26EE04A68756B1FE9A75864EF1B7F41737C57 +:15168F00777BEDF1DB6FF95B14BBFD285AA9BF3945A7743575DF +:1516A4008C67CB1C31B9ED0FE7E415FB9AE349AD9878DC5D3E9C +:1516B900AAF61A1BA87D8DE0D0D483F47FD56853AB8CED6A8D70 +:1516CE001157EB8D2EB5C930D45544BB477493FD595B754AEC79 +:1516E3009FB6F553FEA43A6A1C51B9D1F7EC515EC28EE97336A4 +:1516F8003DCB17BC759527367D92772E58CC776DAAE5BB9F6D89 +:15170D00E05D6FADE04F2F38CEB166F2B91FC0892426ECBAFDF3 +:15172200CF9EE2FED387F59EB7F6F262B677A91B2E3205F38BA3 +:15173700D455CD99B46807AF92587EB13B4D74A083F39BA4BF13 +:15174C0071217D43BA16EB3032FB606FDDF89E191DFCFD821912 +:15176100EA235E1B79279D5F953C6C88B1053FE0CB37DAD7F014 +:151776008388129F788B3A85AE7290F2BC1FCCFA9DF8A6FB9DCA +:15178B0010AF1E14B65E3B7C7A4CE13F4D63DF4B32A32F49FA86 +:1517A0006CD3104F596B5EA6DF3A5F31A744D87D9326DEAB6A39 +:1517B500027BA94167BC63FD5E8B55124FE0EC483B8FBBDA56CD +:1517CA0066F0C3F1C5A85D3127C44DEC57F6A9528B323AC0AF33 +:1517DF00D96D627F734A9BF4DE37ADCDE9FB071B5CED3357FB1F +:1517F400EA0CEDCBAEF6E7CFD07ED5C76C1FFE3589863077601A +:15180900010C3BE65830CCA7B6A6B7AF8CBE28DA526303A46BCC +:15181E000CB732A5D384EF8F4CB67188DA9D1F1B309E5EF06B13 +:15183300E1D331E9F6F371EDCFAC7D2AEB3F22E52774A9ECA464 +:15184800BE7EACB3D1B78E0B5D46B92FA995EC18E1511F8B60C6 +:15185D007C96EC18E4317A866F01F21B296F0B337E6D62EF18A4 +:15187200699E6969D4D712C77F24188AB5865929DFD939B88DCC +:15188700190F70F08FFA790234A4B5FACEEDA1F64EF292D096AF +:15189C00D6B93B8EF208B5118C5B3A33F2083F10E3707FF1B807 +:1518B10021F67738C13277473D27B9DDD6B177ADF0F3098696FE +:1518C600B576DCFB29FD3CE1E9B598E74ECFA5FF20CE4084AD8B +:1518DB00730562BF0D739DBD9F2CF6434331A9B94059AFA36E52 +:1518F00094654A3397A5C37AA7381BF0B258170EC2C732BA3C2A +:15190500B35621C717E9589F484C785A426F35F0D08A7B74362A +:15191A003E6286562CB6FD5AC4BA96B557611C3597624F3D3A72 +:15192F0018BF4DDDB4043693D88735068633FFCA603C4875F9B3 +:15194400F32BF52BE974E08DE57AD3E34F7A9A1C5A5DA0BEB02D +:15195900F0761BEEB69BC2EDB954A1CBA79337C21E5E6686ED09 +:15196E00F593E9F04346032FE883D59719FA30FE0D731DFA6039 +:151983003C175F29FA10113028D1B80EF80D35A70577C08F3B83 +:15199800F15EC92CCC25E37BF8E0EFD285428F540EC7C7976FC2 +:1519AD00AA1FA5BEADA2BE39EF77FCCE75D410FE24048BAFE8E2 +:1519C200A8E085B93B4EF00999C598B16838A00CEA993335F4F6 +:1519D7005B8D25E8FD31FE3EDEC37710FB414A3B6C06E386DFF9 +:1519EC006E7FA97D597EF71525048FB3FA041F233316FB9D6202 +:151A0100BF69D883FD6A137BBB57D3E950D6FF89C6CBBFB17C5F +:151A1600625F767D5894CF961DB6FF8DCCFFB4F5E2B6988F27FD +:151A2B0053DF3715E2733535305C1CDA4EF56CE1C154A5312B41 +:151A400095D3B22AB5D80884DA88DE63A2CE10CDC92CFAFBFC5E +:151A55003519FBF21A87AF8EFCFA2384C752BE16FABD021FF809 +:151A6A00A8F0B5EA8DD7697F1EA96DBE47F5349FF75EE1A1C844 +:151A7F002797826E1BD2E9C249C9B193BA8D3CD02D2AEF32DA11 +:151A9400E013B89683D6C85743F9CEDAF9C2A91554EF6A739572 +:151AA900C573C38286F6BD26760FEF16FB8295246F5682A68619 +:151ABE0045C3A9F70E09EB8657787A391C7107881F3FAD4DE607 +:151AD30058F517F101FD41755663B13AABF6A5CA924673E18293 +:151AE800C657F18EE018BC9E2E5CA84A8D024E85F4B072A3D58F +:151AFD00C7FAF9E51FA7F333E7F1C60F5B7B8DE387CD4365D585 +:151B12001AF58C63BFABD7AE9FCA37A32E8DEA72F23AF9B6524A +:151B27009E7D6B06B45D34C6D0875B49E64D6F6BFB8FAD3D8A0C +:151B3C00522AFFAA64C185737B5D180BE37163BE7F500FFE6E98 +:151B5100BF8101BE3AF5A2619DD34A3333F282D647F5CEF3D710 +:151B6600E8A42B97C0D7BC865DE189C837DB70F62E89B1BB66B3 +:151B7B00B16E12AD72D990EE25FEC7DE506364A89129CF59B491 +:151B9000B1F5378C6159F0994A70455A05FCCA73E69B3F4AE70C +:151BA5001FF558FD5C49B46E9A81A6B751DBD3FB34F8A3B4D82E +:151BBA0013443D5BEDF2F36252A3779C6440740FF7F8137A2424 +:151BCF00B59F375D4AE73B6573699CE02CDDA88D779CE714B2F2 +:151BE40080F0E0E4E9A777E2D9788AC77F98B6CE3F529E37DF4D +:151BF9009F8A7BF0E04CB012FE4B4A53ED46FD050BE783D3CA28 +:151C0E008D02FFE07371566D0F77708D3371AB530326C73E7BDE +:151C2300785ABF5957A6DF472F5AFD06ED515F1BD55763D34CAD +:151C3800F0E6A0C59BF04B97D6FCBE1EA5F7B73AFC67D3C2C2FA +:151C4D0063B60EEDA2056B1BF1C4C8BF583C31CF5FAF8706A432 +:151C6200468737B662BC5BE73B6DDE209D3F32A42D64279AC1E8 +:151C770017C18661C10F667CA1E6EB7E519769AE5C68F381E5DB +:151C8C00F73A95EEA493FA42CA61E2F9765E447C116CAFD595EC +:151CA100376C7C3BE3C15506F6D44CF8BE1DE39DF203E737B4A5 +:151CB60043E3E928D5E9F8D3E4BA78631BF186FAA6C51B12E1DB +:151CCB0057B67963EDDF5AF8157B568493CBBFCDD20FF5CD8A7C +:151CE0006ED1B59F7CA99E649C599D5A6356A5569824E74C9214 +:151CF50083C60CFB4DE21C33F4143FD901C2276E063F6FD2937B +:151D0A00785E51B7DE06BF4CD2DFA09749F9033AF6B5BAEC73CC +:151D1F000BF02D7B50F8330D0B5B4AF877E34C34D94F87CA4E3B +:151D34006ACC1812BEDE4AB2D384BDBB2A794AE877F1E410782A +:151D4900728EA2769AABD453A641F712E388FEAA6ABD67954398 +:151D5E00FCF24DF43FD8438150B4750FE66FA58A17939CAF263F +:151D73003BE676F8E23B7633D96915DA55BD27B2BF0DF8F35FD4 +:151D8800C8DACDADEA7DE6DB3F93EE94957BF52A7505AF225DD7 +:151D9D00FE92EA6D0ED2FD5BF04514E36C0F2F3D9FCE7FAD5214 +:151DB2006E249BDC207BD698C78EDD15211B50B6694D76AC01A8 +:151DC70059D9E44A433E25146EA53ACD2ED5DFECF8589692BDD0 +:151DDC009BC72C3D0DBF8F52DDBB95A7DAA08F55CF618580CB48 +:151DF1006D67BA6DCCE80FAD71D029F257F36BC5AC9029EF99AF +:151E0600412A0399E186C9E2BF7A7E3BCD0B800F7004D5970D68 +:151E1B00F4218F781FEBE76C7C31749E6068C5A774F41D7A90B7 +:151E3000F774834E6085AAA82E21038C1E1E559FE1AFCE26DABE +:151E45002BC46754DE6907766090F41F4A33DD6DDE934E8B36D0 +:151E5A00855EA51C364748472B8FD9B22C6AC939D4D9361BEBFD +:151E6F00F6614A3B2CE0F2B2BD7A0FE08AEE3121A71CBA396BC1 +:151E84001ED13740BBF704ED707E5C55498F573A877DEA1DA687 +:151E99007705E940D1BDA26EE8F5D0E9FDEAB366CD75A929AB9C +:151EAE00CF583470F0EDA6C360C0F2BFBCD97B1E60856E7A0042 +:151EC3009EB1BFA139D2A117E495526526D6701D7AD4E49355C5 +:151ED800774DE7D7A87D9E2F9E7AC72C095D6CCD49922D7DFE54 +:151EED000A8D8D2FF00AED4FF425B16FF37D9D27DAC43E90ED91 +:151F0200971EA6BBB087B08608C28CC1C77DD80C8BB3DCDF30DF +:151F1700E684CE50BB3F249952DAEA8B3D493AED72CC2B66C792 +:151F2C00BD0F918E7BBFD171EFBD7A774A024E857E9B87392E76 +:151F41001CB5F5DB2ECB2F8FC66CCCF6B31F16F76ADB0638627B +:151F56008CDC073B2B4265B6087D3A2D7C44525C444EC819E394 +:151F6B00E1582D9F9DCC69093CBB9E074EB7E852F2040F40BFA2 +:151F8000879E7C1F7CD25F163EB87DEC9B1ACABD4FCA53DF677C +:151F9500BF69EDA7517DFBD97734B6ED1847F4903EF66D0DBA40 +:151FAA0018E4771F7B4D832F2DE089920E87FC80E55689059E76 +:151FBF00227915185BA9DF4DFDF12B8FE8B2FA9C81BE3A7E50F6 +:151FD4002C7A9FD931EB5EE1039C4F3031638DD9C70632FE501A +:151FE90028CFA2CF99AF125FFACE8DE86CA4D384FD04FA0FDB39 +:151FFE007BCC68ABE8524AEFCD7941E8F56BB1AE3C72CC1C63DA +:15201300225F1CFA3CFCE2B0B78867D80758AF213917C7BC7364 +:15202800ADE27073B9EA69F49D233DBCFE18A7726DED852B5BE4 +:15203D00A05F930D5A124DBD635468DFD3674BCF0B9DD8E33F85 +:15205200A1236F09FC1BEA87903F7270672FCD457DC236050FD3 +:15206700887764234E923CF49D3BA8CF3BF79CCE2607054C382D +:15207C00EF437C2564FC1FC6D6365978F986E13BFD72960F9219 +:15209100DE0C1F84C007842787F6BEC82ABDABCD63D111F4336D +:1520A600BA4D879E4FB31735879E2CFA0D73103ABACD2B53F1A0 +:1520BB0067E1EDABAFFF9186337253717644E0ACA44DF848DBB0 +:1520D000381B06CE026CFC581CBEDAD79EBC7789A80FB6CCA84C +:1520E5008533165D346CFD77F65B733B1B9E3B7A42E047AC7FA6 +:1520FA0019C7CC02E8C5935FE16F104B127F9414A53CCDC0ED45 +:15210F00E39E2796FE69CA736728E66976F30978C373E91DDDF8 +:1521240027BDA077AB599C04A78C0DCBF6035D2D7EB6C60AF085 +:1521390094E1F5E9769FBDEF6EAAEBEFF49DBBAAC367D9EAA701 +:15214E00C1710644E83FE1301778D9F669AB7FCA401C6BEB2D2E +:15216300EA034BB0FFE1659D7A70C75745FFD8E6E778EFD81756 +:15217800493E7CD174D93BFDC2D6C19E36E18245474CA78E203C +:15218D00D951852E5C8C117F2797AF6FBA7EDDC2C76FCA9FA8EE +:1521A200DD40FA96859FBFD7EBA4273F003FDF27FC3CFFEF82DF +:1521B7009F97809F7577E98E6D9E6661CE267F6EE1836CE6DE14 +:1521CC0038EC050B1F0BD8223DF8FE62818F9C68A95E1E2F6F3A +:1521E100BE45CC71FB782CF5AEB9ED97B0974B5BE9D9807CB1CE +:1521F600EC1FC21BFBE32C0F2A583310FF84BB0117EE5E369D99 +:15220B00F6A6E3AE9770B78D70F77736EE2E12EED07EC8D5FE2D +:15222000B55F586D4F6DF7056D5FFE505666DC5C56CC71C98A24 +:15223500A64C3EEBEC74667C2CC4BAEEBAE7333244D8E7E3545F +:15224A002E3EA44D2EF70AD8204B204722A4E3418E604D0A67B3 +:15225F002050EEE9944B9EE4BCA461FF0FE736F05EBCB3E449EC +:15227400896FDD4BFA016A5BC8946D4362CC627D0A7D2E76F53C +:1522890059A63EBB65CD74FFA551F8E6285C2FBA64E801D20F34 +:15229E00FA9232F547354EDE27F4CA906B8F8C063EE99034B72D +:1522B3000357276DFE4079DF42962F8FEFD495F33BB5A9FEFC1E +:1522C80086B0357697F56B42B7945917703526D65C86E20BB10B +:1522DD00A743632327752C2EA74EC47D7ED27308BF05F1A1C669 +:1522F200E2A841F301E73D29B94556137CAEF217382B182AC2CA +:1523070019BA0C4C5161776CC799BBF2D5ADD0B1587958D821CF +:15231C00D095271EB07C67AFE15EBE8CE6DDDF3F207CF7C2EA17 +:15233100F1D40333FB731B87B07ED12FD62F76931E5C34D629A3 +:15234600D609D8B89C301A8E58B04787E245F06FB4D33DB1A12D +:15235B00B8D2302CFAD7C3F66A384FE85B47F3883104BD08739A +:152370008C41735BA67FC591C146A7ACB58F9B79BE019E6B8741 +:15238500B2EB31BBCB86B5A2B80D8F711378285D215B1AB0B83F +:15239A00DB94ACFD988ECC5A8DBD3F8FBD68567ED2DAF7B4FD65 +:1523AF00110977167EACB5F4A978543A0F4CF12FA27110BF1F74 +:1523C4007D305A31164897E928B77CA2E21D94DE1B4D6ABE22CE +:1523D9004B2F4B114C5772E258F32AC4FBE87ACB96C1DAC1428D +:1523EE00DB8F6AB5E09123F1FBE89D03BB809BF26BEBC51EA3A5 +:15240300D8075C6BE7D35DF956A45EE8A0FF38D28DF558CFF983 +:15241800761CF31EFA82FD4FC0D1BB73480B8ED9F050BAD3EE10 +:15242D0016BBBE9E19DAED77B5BBD5CEF78C2BDF4A6A17F99220 +:15244200AE7C6D76BE8119E05B99FA661C67108E0818BF1BC70A +:152457001ED815824521F89E16BC734CF8CDF47E8F6065D6BA3B +:15246C00E01517ACDBECBA5F9C01D661170CDBED7C2FCF00EB9F +:152481004957BE1D76BE573E0056D0D881F5EA87C07AD5056B9E +:15249600CAAEBBFDFE1B61EDBA3F0BC3653B5FF7FD37A1E7FD24 +:1524AB00597A5EBE093D2FBBDABDE2D0738676FB5DED5E75E845 +:1524C000799376B76CC0F81A050E8C0977BBE8AFBD7E8F74875A +:1524D500E71FA7FCFBD95086E737782D9E7F5FB2783EB621DB46 +:1524EA0076D46BB5FDF0860F681BFBA576BB4E7B93AE7E6EB0F7 +:1524FF00EBF8E2CC751818B38E6FCEB5E9328FE4CBE5C1ACBCF8 +:1525140013E359ACCD22E69421FC099832624057F1F93BF5DD6E +:152529006586A6D0FCA0AC3DA597F213FA3E9A12DC32E809EAA9 +:15253E00D74CB2C729179286B4FDA437825F2CFFC7BD644B24A5 +:152553003BE0EFBD52D4959D1BEAA82E0FCD0B19B94A7A896F04 +:15256800DD9090A9429E3AF3451CF27448C853650DC14F725439 +:15257D00723D4F9D8FB0DFDBAF4965869EC61A18F6DAADB37498 +:15259200F6DC346CB56FD8F234DA678A35D5F121C3EACBA0069B +:1525A7007F17EC0B189897C85E99ABBCA2FB48E7C6DC34E37C24 +:1525BC0032945D0FC73A1CF6944270D7856FBEFD9BE6F339D379 +:1525D100D7C2AD75DCA3864CF348A0419C756301E917FA933497 +:1525E600B72D10BAC911331264D1D7688EF6150D0A9F0E2B1601 +:1525FB0058B5D807DA5DA66AAC7E2F6F13FB0B3D64EF579AE254 +:152610004CDCFFEDFFC3BD1C30B36DEFF238D159C0EE7ABF99F3 +:15262500F4B6E5F4FECBEC1F9722C609FAB0ABEC88735E5915B9 +:15263A007D237D48F44321BBE2E3FE0FF4F29215EFEAD9B4A1AD +:15264F00E175B1F412A7AD0ACDB2D53F4A5BF1E48D7535C6BE43 +:152664002BEA8A7E40F918952B5D33B5DCEDB18796587433CC8C +:15267900D5A09B5D2E4C79FDD3F2D6C52AECBC2A17FB43365DAB +:15268E006591AFC75C3061C77B237CE26C5D5D2CAF51ECBDC060 +:1526A3007F53E44F7092F13109F989A7113746B6E2C319880F2E +:1526B80027CE3F132F89B399E383A67B3FA9F5886B3F087BA603 +:1526CD00DB388F603F272A6C1B71BE5251E0FF613FAB3807990B +:1526E200DD0FEA75955F18931B9D3D21D421AFE17A8F589B1E44 +:1526F7001C9E74EDA33AECEF63A3F96FC977E57CD9F39EF47519 +:15270C00E951E9335250BAC6FE8EFD35FB2E7B990DB1AF319314 +:1527210075B30EB683FD2929DA5F628FB147D9436C23D3D8036A +:152736006C3DFB1CBB97FD015BCDEE66ABD84AB6822D67CDACF0 +:15274B008935B206B68C2D6577B07AB684D5B15A16669F66B73C +:15276000B34FB11ABA7E8FDDC616D355CD3E49D7AD6C115D55E8 +:15277500747D82AE857455D2A5D25521AE72BA16886BBEB86E5A +:15278A0011D73CFB2A1357A97DCDCD5C21FB2AC95C41D735C7EC +:15279F0075154FB902D32EE5866BF60D57D18CD7AC9B5EFE0F7A +:1527B400BC0A3FF42AF8C857FE875E3E26CE181FB7D6B754E111 +:1527C9008B4EBA3DE9F151A61E475A15A519F673353D8FDBCFB4 +:1527DE0035F4AC48F48C35BEF26ACA1FE1065BCDC7C95E5024A0 +:1527F3008D2BEAC2E34A8CFE93F49F5A785C8C2BB11E522DF667 +:15280800DB55D54ECBB7D3244A8BD96905769A87D292765AA167 +:15281D009D964369A88FDA14B02B2C1AB6EB825F60D8AE037E98 +:152832008061BB2CFCFEC254262AC16651F9F04B5828BD8D33C0 +:1528470075E1016F6899A8272AE2EED41AC549A9CE776631CD9E +:15285C006B95077C671A843C887FC0BBE10F78073F38BC2BA2B2 +:1528710077946E225D7EBD41176D8F2F361DDC3938473FC66D43 +:15288600189561411343153E7661037E200CFD1465C2ADC02FED +:15289B0070A878ACFCA96FDBEF99CA9BD485A661D7C35EB1D235 +:1528B000A3942F8A754A65A129FBC8A6BFC93D2A65F38CBB9EA0 +:1528C500154FF6D9B0D345FD63E9D988ED64F947AA7C42ACE7CD +:1528DA00A8563C48B12EAA8A5891B9F6B3F043F310AF617D2323 +:1528EF00BC8C477FE16109CF32332FA4B6CA91067DA2B241C487 +:15290400A998F8AEF70EE004BFE12B3046E5FC6C19CEE49A35C6 +:15291900840B529EB84FAD33F3D86D04FB6DA63714691D9F2168 +:15292E004D91AC34A6BE67C2BEAACE99AE9FA98648037FD3FD64 +:152943004155AA9389664ABCBD4E86FF8C5209F9ED634A2D354B +:15295800B9CCA81171196A4DA6002E55C012F594521B8B0DB4AE +:15296D002F9F29D595F8E27ADC7DF1C575B847D1D7F1B090F94B +:15298200C82BF818F29DF489B81813CB7844F8D946901E4BCFE8 +:152997005E4D79A2464CAC776BF659FC188F88B5932DD699FCEB +:1529AC00709B75469E6DB7E3F076D9677810F764360195205DD9 +:1529C1002461182CA141FFC1EFF796CB77B0F10EC3AFCA752C4C +:1529D600BAD39844BFC655C35A07B2CE2DD7A472EA449D549F2D +:1529EB00386783E768AFD15516D72431FFF59A9973E3D1FFDE24 +:152A00008FFECD579F3664F575D21913464495EF78E9A197A820 +:152A1500FED7FA918EB41A4A3B302DAD94D2764D4BDBB69CE0E0 +:152A2A0052DEEEFFF243EFD49262C6FDEA25633B3BC3E7AF7812 +:152A3F00476FA9F869EDD7965DB17DA5E362BD6D41FC027C739B +:152A5400845EB160C5395D4E0E1A9EF223ADAAFAAD7E664C9A2E +:152A6900BEAE5EA193637EF68DF52D0D618EA47698F10DF3161F +:152A7E00E91D1D7828603FAD1D7EE8974B0906A2E92582EB9C07 +:152A930021F17DFAD736BDCD6F89D05CACEC330967F1EBCB57B1 +:152AA800D5FABAA9BDE8CE617624176BE5C33E1F7483DD077C9B +:152ABD00ABDFA1F4FD07ACDF2FD8BFBF7DE00CCDB7C9EBD3C29B +:152AD20060477FD89FF09C3180B7ED6C8CC7BF935BF7C413B97E +:152AE70075581F3830FE356DDEF9FD5ACEB937F4BBD985DA799A +:152AFC0063A774C41685FE62AD2F8E8BBE96287FAE4F3E7CC918 +:152B11009C27BD46EF2F98BEF8B1A5D88342DD130F9F337CC974 +:152B2600DCBA912773EF10671887451C98E3090FD90CCA090325 +:152B3B007DF9EDA1CEFAD069AA5BF9078EFE28803BFABD611FD5 +:152B5000620529BB8F2B02FEEF1F7F9BC66081BAB70B6BB57987 +:152B65006A67BC27CE3589F49389CA1F1AD05192A4777CD58762 +:152B7A00F83ABC6BA2F2D726E5DDF34BB5E68E28E5DF115B5586 +:152B8F0007BB4A8C2DE59821279F2519E9AD8B8D1DAD63C60920 +:152BA4006302BC47EF317ED653BA9C3C46FCD3297C13ABEDD81E +:152BB9006D62AC197BC53E47B5186706F725F7D2388B73996858 +:152BCE00AB305E8FBB8FF13ADC113FCA97ECA33AC68C36EC2BC0 +:152BE300261386E4231C85C74CFC061F627C9CF92EDE0D923EE6 +:152BF800493A7F3261DE16E7227D8CD2F11BFBC81395DCF0C751 +:152C0D00E4BA00E96B1827139583E63CB22746AF7BEF205C9AE6 +:152C220067DE4FFB1482A789DAB8807115EEE71324839BA85E80 +:152C3700963C68BE91F1E7EE32FC8481300177A193D733E374C9 +:152C4C00BFF0632179D61D39A7FDE51772EBFA59A7D61FEFD3ED +:152C61007E5925DFD14FF6DADC44AFDEB3936B3D0D17C55EB4FD +:152C7600927ABAFFB645E59F11BA5B383E8C9824810509C4C806 +:152C8B0032E627459FAC182F3EE8A37111C3A55AC6DEFBDB8611 +:152CA000B41AF18A5F357BC6B806FF415FF22095DB0D3C8B58F6 +:152CB50057A5A9A7CDF9A9AF9BD5849BF9D4D7642EF634778BAF +:152CCA00F159ADEE16BEF1A20E85236E9FAF54FDAA217CF63673 +:152CDF00714EE50CC806393662D4A7BE437977D358E9A579EE05 +:152CF400A08E3A3D6787442CE5B6BF60AC0CF62FD980885722D7 +:152D0900AFDBA5539F0E78D6EDD3B7E4B1A9E3631CB16EBAF850 +:152D1E0057DE92BFFFB424E82262000553F033EA177E46C029AE +:152D3300E2FE045942AC5F8A78669FB77CBF906E8EF56AA5A9CF +:152D48005DFDE1D4F3496505D77DA403E7ACE5BAAC72D3EF4371 +:152D5D008CB783BC3AD2B714EBBE25EDC43FEA102F8DE3F709B1 +:152D72003364FF464C0D4BEE937D9AF2D7210DEBC2BE8CFF7CCB +:152D8700BF8881E3016EC67B8D2A4107EB8CA2447637CEE55AC6 +:152D9C006713AD3DBD37A92E896000ED413FA9EB981E5AD069C0 +:152DB100EE8F58E7DA104346FA032EF47445D0D1107E6A8AE003 +:152DC600EBE78E5F1636449788B723A748868D4F0A3C07C84604 +:152DDB00F60B1F837E116FC72362565BBE6BCC78CA443C46C088 +:152DF00029A5BEC2AB539FA875CB76C874D04FC8F58C4C27F975 +:152E0500BE25B72598FA8D29E22C1E07FFED32F7FC2E5D520F81 +:152E1A003F3B9B06C07130B5CFF0F05E3DD068C5BCF3906C4040 +:152E2F00DC763FEB5DE2271E99C77A6B41BFAD2EDEDC6AD1C9B0 +:152E4400D88E7BF99556C15B4437FC96C5B982B888E3047A8367 +:152E5900BE22361FC632D1733A2D6551D6A2C387E1F623D3083F +:152E6E003470E3DEA1C7C7A04181A041BF1DE7284B8B0FA58182 +:152E83006B6E75F03FF62DC4A72C0ABB69511CFB64ADB04BA3BE +:152E9800EDC3D79EFCE452259647F368BB01DB13B28A7F25B730 +:152EAD00EEE2BF38F2C79217A544ABE205DC94A84FA01DFA68E6 +:152EC200C53AB2DA407BA83B130F23A31F59F42873D1628780A9 +:152ED700A7CB3AB740EF11574B49ED33253521F808BF35D77979 +:152EEC00E0A0AB7CF0F399F8E022AE783F1B12FB163ED0BC7DCA +:152F010048F3AB5E218B15F007C99EB288257B32E38EFA2C6D48 +:152F1600C1FC4BF735E7040E689C06FB7F6BF53735EDB313D89E +:152F2B00A3290D75B596D1DCAFB2E4F1301B3B1E61A9E3D72E7F +:152F4000A4F3E93E4CBF87297D58B3CBDF2CFF9137A7E6AFB6EC +:152F5500F3631E1FFD8DDBFF14F32C8BBACB8AB8C362CF8D1B4F +:152F6A00D79F94EF6882BF8B3A1AFFEA99535A2E9917B2DADB5D +:152F7F0085B84805EAAB5D38FF68F9838F8933508A3A42764A45 +:152F9400C2F0A716D5C97F93CE071ECE5E4AE74FAFD30D9B3808 +:152FA9003B48659BD4678CC99F71D2890C1173C9E2C33F330520 +:152FBE00EF5AB19D267A483FAC233DE8E3F0E6C4CF7A8D84A7CE +:152FD300CB6047E496899F7133E1E9379BD41EF337D7313EE251 +:152FE800B62DD26E5E86EE13361CBDD48AEB6E1C34A0034B3494 +:152FFD006E003BFD3677FC17D2FBC25113FAAE83B39387B2F8C4 +:153012006EFD7516BFF3110B22544A7A79BB7196E0DECE629CE6 +:15302700A5C2FDD88FF2A7AA8DDCD3B5FAB7E28B6B3B972D9B72 +:15303C00A22BE631F8892E13FA539EF428C98F35869A8AF63372 +:15305100E557A6CF57A9C3D7D4D213172E2D205BC453AE8936F5 +:15306600105F167AB6B7BD562F8AD4D617509B472BEE5C3A3F3C +:15307B00A5D25C576D94A6C286E46FD43B9FADE5DE31B2FBC612 +:153090009799CE1E37621B0A5D5D6927FDB1AA56C65E6AF49146 +:1530A50061663C7CC0D785F301FF49DC53CB3D7764D7834AED9C +:1530BA00B882D5B69C0A939C5AA6414F9FA74A61118F54C869C1 +:1530CF00B241A83FB22B2695357F3E3F5C3676502FB3D7338382 +:1530E400340F63BE65E3AF9801E9B25E5759F419567EA695B16D +:1530F9002B5C61FFB03428BDABEF53BD75D005C32413E74B43AF +:15310E007A49E864AB2FF20F4BE6D3DD73AE4FF8AD601D6FEEF2 +:153123000AC4C23B69FBC7C4F9159AD78BE327F4C07CD24B94E8 +:153138008EE18FFA3F97746FDCFB97E7D517C7F2C82679C5604B +:15314D00A9E78FBF41E3687EEA6903B24AC411A0FE07683EBE55 +:153162005AD6BB2442BA0CE69B07BC86D05F7EFC0CAF75749694 +:15317700ABBF4BDF546719FEDFE99BEA2CCB6EA6B344DFE129A5 +:15318C00E7FC27640CE1CA57F985A505620F0F783BB53478FAFC +:1531A1001754FF29BE9E70B77F99E19CA917780AC54732780A6C +:1531B600A516D5FAAE604FB963587EFD14E473685E6A562DFD13 +:1531CB00368A5325E25E905A20EE06C9F199FA4FF369BD67F568 +:1531E000BBFAE56B691FF080BED6D87D9F78DFEAFBFC19FA8E7C +:1531F50032C3D73E7EFF1710DD4B2147A33DFD6DBF9966BF5070 +:15320A001FC55AAA8B9E6BDD79A27DC63DAC9F6F201D3DF78709 +:15321F00BD4B54F5345920295E2C91DEA55C3083365FCA381F10 +:15323400A4FCC4DCCE2EF280745587DCBB65C5BB7A78EC3BF5FD +:15324900B73458F8BC85BD63F975517BB7C05E095F143805CF3D +:15325E00C1BF133EA2E5296F9D9367EEE94B19BCCFA5B28ADA53 +:15327300DE1F2F4CB420EF56ECE54447FA117B31E7CC29BC3BCF +:15328800E0397B4A37D26427D1FB6AF50B4B71073C93CBF3EE4B +:15329D00D8F6D04F491FFC89E1535F3E50A3FEC85C3669F73195 +:1532B200BA6BD88FF8AAC9F5DC7A86ADB46BF8CA72ABFC49C28D +:1532C7005BD0AEEBDAF2C796DECE5EA813B68E2B2FCAA20E77B1 +:1532DC00B9B394A7E3A90B5A58FD8F4B908EF99154E5CFE1F98C +:1532F10019CC91D15D49E89F285B803D65C225BE1F33BFE7B062 +:15330600C0EB3C957402BBFEA229CF736B3DD6737F813ABB967E +:15331B00EE86A7C8D2CB51BFE7EB7B74A1037C876405E9576696 +:15333000E4794D8924F4529A3B443C16C53A83F361FF34A7745C +:15334500495DEB75F8193265A7987794129A3FEC7947CC41785F +:15335A00F731E61F67EEB1E7A119E71FCC3D9883EAC599FBCC51 +:15336F005CC3D5316BAEB1DA5159A9FA2B730E74099A977C6AF3 +:15338400B7B9E5BDB4AF20C9BB0A08EEFA48A2CEB1FF4A691EE8 +:15339900439ED5EF39F4EE349AEA2CBB716254BC37F03E4CF834 +:1533AE00417996BC6C486557881F39D98D5D3C37998817533BB2 +:1533C3004A72A41F632E27758AA34EF01A78AE5AFDD901F0D4A9 +:1533D800C5F71DFDCC8699607DA3E7591AC3EDC6D65F58F3BB94 +:1533ED005897A5B6467F951D5F8190E5EFE1B3CF1924432C9F18 +:1534020074CFFC2B01EB77DCCBF23748AC707B0ECBC77986F8A2 +:15341700D8D46F3B4DFC2D4D4C1711129DBA46FF6DF46FD0FFC6 +:15342C0030FD8FD3FF04FD2B3FA2F73FB2F28ABD83A0EAC46896 +:15344100E467C7F0E1884A1DB1F06F555B97B0FA5F755EA47C51 +:1534560015FDCF100EAE926CBE6AB2FA761EFB4B7B9DAD7E8045 +:15346B0027E9B947F5B62834AEC7DE465F470DC4BC14E73EEA46 +:15348000BB39DAA977F43BCA1FA7FCB7B2BDCDE299DA539A5FFA +:15349500340CF4433961C0BF36B4E298CE627B39DEA3EC7EF867 +:1534AA0063217634D5592CEA7C45B429621B7D601DC77851E412 +:1534BF005433F2A3CDB9A11BFDA9597082F7B2ECFEADF0DF0892 +:1534D40066CFECBF799A1AA43993D59FE216AEE1DB316CF5B34B +:1534E9007E888B36C73B0DAC81948C1DD3156AB7247E54878F79 +:1534FE009EAC4E4DC31A888FD202E35D7ACF84A7C5FDCE47EF92 +:1535130042CA7FD3FD64878E601FD4D97725F8FCCC155F697AF0 +:153528000CA57FE37B9C131A0922364775EB55BA7B953A1D3188 +:15353D0072FDB14A3397CA5C0BB142F9BFB61B56BC617917D2C3 +:153552000629CD1F1BA03967917E71B9749757E9D0C7290DF1AC +:153567004BBB903F5669E07C8D8A73A29426C706CC61A4D3B355 +:15357C00417C7B9164217CFC6BE63271C68307B23609CE1C5FF6 +:15359100F558F1B2B6219DE007C079471077F45DAE9C7F464330 +:1535A6003F4AE11BA48C709FFF98BE8E6CB339AADC92973A2800 +:1535BB00E2B610FCC5A114F2EFED90BA7B853F27CE18DE966C99 +:1535D0005AA2F82D5F0BC466982DEA1C3AE0A33C3E2B4FB034D1 +:1535E500292F918EDC589645F304DE0C9AF7AAE658DF8082FF11 +:1535FA00BDC3E7E373E0979EC8F887C9EAA4D95A427822B92460 +:15360F00137EA2F4CC66F0E72F25BC5BDF3CF96B737BEA6F0F36 +:15362400C897DAF5CBC553EBC7F744DAECFABDA1B156CA6B50E9 +:15363900DE7ED4B58764E75A196B3AED343E2254FF6AEE53F13D +:15364E001C6D853FB7447A2EE9C2A65FD5CDB504838C33722494 +:15366300A7F17D95F96A3B87DCDC537646C37AECAAD43F13CFF4 +:15367800FEC05C4DF724F1C25ABAAF4E7DA61FB410FEE76AEDB5 +:15368D00011FD5514FF59706587E581DE0169C5FE8079C388F73 +:1536A200BD92F475D8309EF258EB9EB2360DF23E42EDC4A82EF4 +:1536B700CA773C4AF7CDF41FA1FA733167184D7C436AB919A3B7 +:1536CC0076A2A9FDFD38F3B09ADA89AA3D070E521E8DDA3AAA9F +:1536E100D8676C4987403B84C0923D6549AD551D306304D7662A +:1536F600AA7F82F07335C00A7D54E632DD714E9EF8CFBC46CFF7 +:15370B00ABA88E8900CE1924F8167A7E35007E575BDFA4FB6AE1 +:153720004A93296D989EFD418B46D371ECA697F7525CDF4C7926 +:153735008B55B939C745CFB03A48B8867F31F68427699C0F9A63 +:15374A008A4A73DA349A875F9B2AAFE12FA284734806776564EA +:15375F00301C123057DF4DD38107E71CB78D7051CE386594ECF6 +:1537740018B4E4DCB663960C8AEE35E0D33217320A6B58888D3C +:1537890019957765DADD3669CBEF1E9249581B3C684A65713D24 +:15379E00E37F4678A0692F9FE62E23389BE5E3AC06D9408DFDF8 +:1537B30012CB273E32A89F8D7E1AC705EA82CFACCA63F9F3E96C +:1537C80019DF929195DDFA28F169BFC20ABFCCAA1A494008FC7C +:1537DD003E42CF09C5C26B39AB6A8EDA721FB240C04675602E4B +:1537F20088501E12E685CBE8AE282FEA997874341F5FA8686FF7 +:1538070084CFA788BD46F7ABCBBDCD0AE5DB5A7CE31872C60954 +:15381C00F6CC300E2798F50D3C278F9FF860A7FD9DBA72D5DBD0 +:153831005C4DF5E4975F213A1D9A820B85FA73167CA3DC26CE74 +:15384600D0EC8AE13B033DC613915ED1FFFC4FD3FC46F800FFDC +:15385B002D25B4416F7FB508E30EFD7AD1C01CD1C83A455EA932 +:153870002CAC77E663AD63C0AC72FAA5741B32E916D5E0BD40AC +:1538850017740503FE7E0AD581323EF5457AFF2B33BFC82AC7C6 +:15389A0094174DE0783BE5CF75CD5B6AD1D4F59B6B45AC3048CA +:1538AF0079268AC0F35546428C936A314EE0DF0499FBE6F5749D +:1538C4003EFC750AE289466FB45A57D54AE3CA72A97994CAD023 +:1538D900382EF4BAEA2FB6CFD665ED55D598781B01B576EAA8ED +:1538EE005B39FF7B22D6307CB5B09624931C95A9BE2292F7E8B6 +:15390300C7C44303F50FD2337CAD64711EC8D603E0E3F536F634 +:15391800F82CF8E5D810C9A4170D712EDDD255D3C53407E3FBCC +:15392D0055B2FA8C69CB9300BE0D09F926C33FC2FEFEC424D5C1 +:15394200F3E318F1606CC85E334EA7FF6A6CB0D14FBF713687E5 +:1539570045DBF9F642969F5B4934B4EBFE2DF5DDE90BD67050D7 +:15396C008785AB230257F0FB0DB1458D4E7F0AA80F93158B9A3D +:1539810071CE7372162BACB8981D3F326414D96517C986FC2802 +:15399600FDC4FE9B809FF409C0E21D233B3B3A4A750D4057248D +:1539AB003C7467FC45BC946FB480E5DFA30276AB6F778D250892 +:1539C000B735A60337F611FFC7B19F1CC5FA83A82F84B58C55BA +:1539D50007A03FE3BD903D36BEEAA7ED4F59E36515B7F15B828E +:1539EA00FD0F3FE5298EC9CD9B73B26347C9AFC1B7BB047ED1E3 +:1539FF00D6BCB141D2A306B1A79816E71AE9AF3CF242E3453F3E +:153A140070F373DD194F23F6F95EE80781F1A7F4C0F9255AB02E +:153A2900BD419F97929A049F19DD7C07CDEFBE50360E0960AEE7 +:153A3E00639F6A862E3096EFD0CDEAFB6FD177AA0BF97136C947 +:153A53001FB3E28A20CDDBB448C46C9745DC120BA6BF2298E058 +:153A6800DF081AECC7593A9A0333F44D791BA103CAA9534601AC +:153A7D007BA57132ED6D9E97F23607A7F58164880F78925343FB +:153A920037A72BE1183038FCE84F9D30FA52DE9650D3908009B9 +:153AA7007066F4D570B5A08B22F42AC0FD29EC41091CCD8B0F3C +:153ABC00D43B78D94C32D76BD3CD473A5451A5D468F5CDC2C5E5 +:153AD10075C1E30306C64D89DDCE3F52F98FD3DF85D4DFAA4288 +:153AE600F437ABCF839FB723662FF1815F75F529F6B2D117930E +:153AFB00B27D52AD3E59F850459F9CF3D2363D44BF0CD798284B +:153B100076E10E7A01F0E6F4674EE84A2BC9419A7F7F6EE6B539 +:153B2500D3F852F6F0373C969E087C6C60D9710F19B839730EAD +:153B3A00D7D28BC4B96ABBDC412A071E49A28C4B9E857F379504 +:153B4F00FFFDEA51923983FC4F2343B5CA8E11D12F5FB2D374B5 +:153B6400FA0C79017E2F16B1E59F35DDB20973899C7CD6EC230E +:153B79005D5321FB3E4032DF9F841CE3A6D5CFE12C9D934346AA +:153B8E00A8E984C04788FA60AF6F171440BE8AF1C5752BEEFC13 +:153BA30015D1DEC2152FB8C697859FA2D38322FE2F70F7C8C3D1 +:153BB80096BF2BEAFF0EDB4B7C3068049A3A6DFE1FCCF0FF61C9 +:153BCD00E27FC0073B05EB7C820F62E003C3E683D10CDFCFCFB8 +:153BE2009FCAF747057F0E66E9AF8E18A82BCBD3832EFA774D11 +:153BF700A33FE0D96BF537293763ECB8C70C7ECB49C4324A1863 +:153C0C004F936CB360B6FAB98BF8DAE1E110C1574C7CEBC07AA5 +:153C21008D602D2758DB7C37F2ECABBF01BFBAE08D11BC311723 +:153C3600BCAA1B5E4B36BAF502A5A953C0EBC8216B6EE8123030 +:153C4B00CB31CB87CF8824DA8A5C7362EADA541EC4B91256DF0C +:153C60006BE0FB53B01DB5FF952ECCF01FD92E6F2256C061F98F +:153C75004E2566D92FC591A33AA972C52595724BE07CBFE6913D +:153C8A0058600EDE8D8F18CAF9A426930D739CE055C8E6958910 +:153C9F00C7B0AEE5F321561CE721A2A74AB64FFCA9DE960EA415 +:153CB40077FD33E6910EDFD953629FF44AC5DE3BD8F8A8618648 +:153CC900A516D4539ED88B98C1C1B988EF41E9896EEC77ED3513 +:153CDE0065AA0F7B61E237B52B8BB5FABDA62887B68CBD387FDC +:153CF3003CA73C2937B65B653AE26413E16C936F2DD785BF237A +:153D08007C526C9B08B0A2FE9DABB996B36E528FD370E9FD2C8B +:153D1D00D7D06799CA94278E6D02FC98CF010B60036F2E2318BE +:153D32004ACE9FD4E662CE7FFD59BD98719A2F92DAB7302FD91C +:153D470075E2FB086DD4579473FABE8BEAEFDA7742F851827F75 +:153D5C0044DEE84887AFFB9FF51460A33EA12F6CF220CE5EA6C6 +:153D71008107D29D39F0B9142C4BEF1D5C5CCCE0C16A2B830789 +:153D8600ACDF8D5B78087D576EEC5A873DC921DE4EE9BD185FB6 +:153D9B008413A4C13644AC330BDE538483631AEACF59F76B7D0D +:153DB00087C0C3312D40FD030E149C3BC6DA3BF4326A0B310BAB +:153DC500C3D47E39C941271EA1751E24CED93B8CED29EBD2DED5 +:153DDA0023DD754198FD61952ADFE5C45B1FFEBC88472874DE64 +:153DEF00D5C2AE5A7420286268EE16DF804059E2EB7CFA3D8C92 +:153E04007DC0F17F72C5B3251B113184845E087F7AF8A685976F +:153E190071863C4ADD01D249C6E2D5DE16C957A3CB91C5FA20AF +:153E2E00C18AF80B48AFD0FA750573907A6FA34FFDA346457D70 +:153E4300A0598EAA3ADEA54847C77DB3388FF4E722966149836F +:153E58006A5AF51E860E34B68CDE5568861E8E0F36D6501DD54A +:153E6D00544795FA40A35347A9783FB58DCBCB1F10F5FA45BD41 +:153E8200BFEA70F25ABF0F1B89E57D778A33DA0D13565B510BB7 +:153E97007EE0EAACF0EFAF36A3948E39F62A6385D2EAC5BA120B +:153EAC00818E68F793F20D8A7C61BE01E58DC526F28ECD90178A +:153EC1006D6F07ED92569E8337C9B30163D3CEB3FD2679C294B6 +:153ED600C76FE7D9302D4FAE522FBE37847CE095ADCB7F762708 +:153EEB006425FA21533F719F43F2DCA79AE64CEB596166FBCB27 +:153F0000638C2A8363D86F147A0B3DE34CAD88371B8D0BDE2D37 +:153F1500B1CECE67D68424C9E2B74CBD549FEAAC1F093F34B224 +:153F2A004F7F90C3B07E029FEF94A06FB6BC150BEB8881746A9C +:153F3F00D3AA9FDE958C3FA707CF3FA7C1462DA1B1126C1A1181 +:153F54006397F836A0B013F598673FF7560E53E3234B133497BD +:153F6900FBC9362A461F146E5A3E6FC233A400318BFDF1634B40 +:153F7E00A04B237F10F53B700839DE65C11749D48BEFFDD9F533 +:153F9300CE8F0F2EAD99566FC60EA6B941949F617DE61FEDF10C +:153FA800877EC15626788B2F63DC2855D9F2EE785B347E71160F +:153FBD00EB9F662877745A391A9F379C27B4CA1FE23F9FA1FCAC +:153FD200D68F50FEDD19CAD57F28BC87F89519CABDCF3EBCBDF5 +:153FE700D434FD0AFC1274F31FD6D5FFC9F54DBA19DEC7AF7EC8 +:153FFC00F0FB890F7BFFEF5DFFB4F77EF778F8A0F5D6FFFFFE71 +:154011005FF55E71E1BF789A7CFA7F077E9B3FA69D399A78FFE4 +:15402600C6F1F061F5B9F94D2A3BA2F779129B3F2ABF61BCCE52 +:15403B009155FE79711EAABAB553896D5E49C3DA1FF8828EF8BF +:1540500077F80EB8FFEE6E1D631E3A823FB0459FB5AA5B57D5B8 +:154065002FF15977B7EBC1755CF34B957AB0A8524F90CE66CB4D +:15407A00874DD7482F5102D53AEAFBD7D675680DD786E173B5CB +:15408F00AE4A877F33BC776435A7E57192F925FE4ABD605D8D23 +:1540A400FEF5358BB58A758BB5907FB3DE99F37B1AF6A316C828 +:1540B90031C4C70922AF2C7D4217EB40ABDA850C822CAA284A4F +:1540CE0068F08372DE178BF78B756F202EF4DA8A07E3BAF0CFA1 +:1540E3002438CFCED0FE4ABBFD426AFF10B55FE26A1BED9653F3 +:1540F800FBC827EAA5FADD6D5FB3EB9D70D59B4EFF34ED474C7B +:15410D00C55AD6B29E4C18D41DCF8971E022CDACBA6EA7297B4C +:154122002EE1C54F6DE6AF5D4CF8A9D416F86BF4F99F965BBC93 +:15413700AC7D63C51FCB2D87662704FEB12E457378106BA2B712 +:15414C0009DD240BBB881D01FD90C59F147D2398CEDA308DA2A4 +:15416100EFFE0D7AC5BEF5BA54E4C096BEEEC0D648B095FA2B21 +:15417600457A9C14638756F94535BA5FC0D4AD2D284AE83D3BB9 +:15418B00F764F80078FE6D3A6DC3C0443F71F6CEDA779D78128F +:1541A000ED8EDB7048655DF8269C6F36B76008ECABD203D41E5E +:1541B500FAD662FBB8C3394CE0252F8B970AE29BC2B54D7AC9E4 +:1541CA00BA7A01CFEE9C6EAD80F052E84FE8B92CB1718FCD975C +:1541DF000B45DFB3ED5EA1B60C7A17207C11DD8B1D1840FB8A9B +:1541F400D51B34D8DC15EB3668D3E94F83275020CE13B2828A7C +:154209003307C57BE95C8D5EF2604C97D997F45994E780C44203 +:15421E005EFB791F3D17AE23F8884F0A8BEA75FEBD06EDD0EB49 +:154233000D5AE1B9B57A09A7B47DAB74FED97B88DFEFD140FB92 +:1542480012C265C55A0B07724C6A51D9165E4F38F34A0FEBFE75 +:15425D00580E62F807F3B15753BEBA7596F4A8EE9757EAFE153F +:15427200D4D6DD8FEBFE55F7E87B73566A5823975764F3E7852A +:15428700AC3324227FA2D6CAFFDA1775FFAB0DFADE9DB59A97C5 +:15429C00E6ECC0F7366B159FCE69C177627CF1DA8DF9630D1B06 +:1542B1009FC6B78679AD5E71EE615D3ADBA073CA2BF9B2F8DF16 +:1542C60086311D12674E362176B4AF9DCA9D6ED828ECDA65ACCF +:1542DB00253710DE981758B6B1A26BBDB69B6401E982C5BBE8C3 +:1542F000FE879031FFF331DDBFAB41870DA1AA8F72B16F98F838 +:15430500A22EADFD922EDEBDD640EF6BF5BD842FD01C7C0DFB89 +:15431A00ABE09B524BC539C21F6FD74BCE7D512F3CDB2DE8DE86 +:15432F0043749F45F42E88F08D6E39045A835EC25FD7A623F818 +:15434400F06E82A505F0138E11377A1D3D2772B66AB3A81DC03C +:15435900DFB9D37ABEFB7ABA0472C8F98DBC34AF6C3A4869289B +:15436E000B7E36C98C04FE20E7C8BE9CE3F0D276CA237CAB09C3 +:1543830086ADF41CF8DE7CADE26C29E1B3549F896F7EC9B27C78 +:15439800F377CCE21BE0BD80F826E4DF2A70F1759B77C03725B1 +:1543AD009CD2A6F14E77FCBEC70A425B8826B1D66EF6E863B372 +:1543C20042D156C9FFB8EEFC2E8C3CFA186833AB7DFD46F67A95 +:1543D700CB46E75EF1AE477C1FA220BE7E63E158CB46299FE89F +:1543EC00FC894AEE25DC5F277A0367B70BFC7B5A0A7907E1FE98 +:1544010071C2FD1E21B7DDF8CFB1F19FB0BE4B11947C9FA0B6CC +:15441600A39BCE085A8057A29B46A7D102DF6D7BD0A605C9D76D +:15442B00E2F52E5ADCEAA2C57BC287303B8677D2F8ED75D106C1 +:15444000EB55A03BD277D8F4394FB471E8B1659AFFE787D1E3D1 +:15445500828B1E7F65D30363B8C4A6C50D7420DAB86991177966 +:15446A00E4B1DCC8FAC7D876D6E21F7B64E32C65CBC63CF69F69 +:15447F001F2B88FFC946FFD8A3E277C51F8B315AEC67F43BF207 +:15449400258177794725F7908CBD9E17E5050EDE696C16FA775A +:1544A900929CBB5F2F5CFBD414BC17CC84F7AE85A0B90BEF3177 +:1544BE008177A7BF6EFC936C2FBEDBC63FD67C30361CFC17BBB3 +:1544D300F0EF116B37167E7B6DFC164136D13BEC33BBF9DE2957 +:1544E800FF4B21FF2D9AA19C887B69D3C1C279FD14589E408C43 +:1544FD00AAA4D48273D5099237B954C72304C3A17B37EB15EBF0 +:154512009A34256789969773A7061EF693BC61AF376C3CF4031B +:154527007A776EAD569CF3592D3FE70FAC77D2CA8D6CCD3D1BF6 +:15453C0077C73C2D806B2170522ED6B603B9AA47CC8548473C72 +:1545510037C7A641FBD89BCA71E6687B9E403EF80E03AEB7C9AB +:15456600ECA43C99F1FE1A8D77CC5117D26905EB41D003684EA5 +:15457B000BBE6AE7FF163D57BC2BE35E7CD2EA77C1FF01EF9849 +:06459000C0E6B892000035 +:00000001FF diff -u --recursive --new-file v2.3.47/linux/drivers/atm/pca200e_ecd.data linux/drivers/atm/pca200e_ecd.data --- v2.3.47/linux/drivers/atm/pca200e_ecd.data Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/pca200e_ecd.data Mon Feb 21 16:32:27 2000 @@ -0,0 +1,906 @@ +:150000001F8B0808AC5A10380203706361323030655F65636428 +:150015002E62696E327D00DC3A0D7054459AFD261333136278A4 +:15002A00192663E02479728060A10E9063213F64F0700F3DE05E +:15003F009E6CDC7B2F3514B35EF0A28B9A5A731E554B91474C5C +:1500540034E11AB6692618B7609D8404A2121CA8648D7551435D +:150069009DA578A56C8AF276A9AB829DF3AC92DD52CC5EB177A0 +:15007E00D4CA32F77DDD6F665E263FA25B775B7753D5E9F7BEA8 +:15009300FEFAFBEBEFFBFAEB7E79F4A91F6C270A21A1870849C1 +:1500A8007C974CFA8536C11F37B9A99FFEAD9C49302569258321 +:1500BD00D8EF4EEE6E14EF59E3B3EDFED3E3C735EC67E50822CC +:1500D200A9FE0FFD29BF7CEA97A26F4EC993D537AF13234A5E2D +:1500E7005EDE94F3BF245F4AFCF1F129E7CF9E866E0ADE2C3919 +:1500FC002BF0237F849F3240F688FEB5EC75792D39E3BCB43E9B +:15011100C9A9F54BDE24FFBC9C3C6987DDCD33F3938CB0674E4E +:1501260078D6F8D7D63FD9DC8CEEABDC4824B2F9DC949E391965 +:15013B00FED7BF11FF975E7267F17D1CFB4BE77E3625BFBC0C26 +:150150003F0FF9BFFF5372CB72671A1F3D3EF99DF51312ECCF0D +:15016500C070095C0E5FF8FFFE4B3A7E246851FDD31C5230FA46 +:15017A00FC0A35E009832F79ADB5E45140A3A4743C8CE3E39F62 +:15018F00C35BB09DEAFF05BD7A95BB3DADE6B56DADE538465425 +:1501A40052C90E11EF08B4773A8857FB013CB7112F090619CEAC +:1501B9005B125380AEB695F80197D874FE9A9022A5D554ADE572 +:1501CE002661CA73EE80B5F5F26AE22D7F9A78FC814838484AB5 +:1501E300E8B36DBD4D843D4C4930CE42B06FCC091861CFB9BDAD +:1501F8002621C3B438D010BE6DD7091AF29090DFEA334930C6AA +:15020D001187E86D9CB09E2EDF18033C8DD220A9BB6D57390DB4 +:1502220011D2D8B26F23C02CEA0FAC0EB76CBADB3C4F48F1BBF2 +:150237001157A5EBD25FC0FCCB804A3412ECA211D133EA167DD2 +:15024C003B8518510311A53A5FDD62226D9C4BD46AEA567ACCA9 +:15026100362DB78EE8A7683E21017F201E4E927EEAB6169944DB +:15027600AFE1ADE3AEBAC0C53534B0EE4194CF8AC2FE47C6065E +:15028B007960DD5253D1FA6834346000BC45C0D909BE0A681025 +:1502A000BDD7BA4BDBBA12ED8A7C09EB8EA79BDA6BF9816681AC +:1502B500F70EF3723259F4518D59F578B3AB0A66E7A3597F0E69 +:1502CA00BA90E04E5BEEC669E5765D2A33DD6762936427C1D5C0 +:1502DF005CDA40CA8A7AA03EA807AC0147BBA02E52A72974180E +:1502F4007B956F461DD851EB3EA14348C8A0EA9689F2332DA72B +:150309000E7B941FFB00D8FFD6801526637B69AB8FCC22A5F03C +:15031E00ACF65863355BCB4740B7F5A05B6A3CEC239954156CC1 +:15033300E7B09E9AA7F084F085DB760DD171378910B6285EA406 +:15034800F64A5F403DE05D8BB4C2F800BD8EE3418BAF06B8AA3D +:15035D00EE81F5E96393DE6D3B92E0385D564748698085091946 +:15037200A79EC256E0D34F49792B1D759310AC032BD6FBCDCEAF +:1503870038D845EFE5456A87F95932097ABB5B050D98BFE30F8A +:15039C009CDF2BE6B767E667E6C6EDC6D24DB7E7A56AA4888777 +:1503B1003626DE3B6D253EE5C5810BE19CD8095A7CFEB241D8BF +:1503C600765A663C6DAE8CBC4EF7B70D35420264F51833C16105 +:1503DB00A6438F32018C232C303A64E29A23DCADBDCAE604CE52 +:1503F000C2DAFC0BE48392B027D20C3E546386122FF0964DDB3D +:15040500C0A7BEC35A366D323B120AE8B357F8531ECA1ED46DF0 +:15041A007F6AE732A6800FFA49302E6321B8C48EB97E560BEFE0 +:15042F00458110CC6910FE9B84D825C10415992A67940623CBF7 +:15044400E9EC584E5DD1912DB4E84C9DA9C486689188ABB8F0F0 +:15045900BD43E494A124DEA49DE43503E75D87B4D6F9E7F81CCD +:15046E00E748EF05F296419A062866F84EF23AC04791363CBF24 +:150483000BCFC31CE5D213EF71C44759162BA4E81F2077148DF9 +:15049800DE677E1BF429501F117ABAB5A3E037FD527EFD21DE68 +:1504AD0072EB2653890C502FC844D803BC937403BD7E2113CE66 +:1504C20027FA51FE0EC4AAE7DCA04906DB38E62BF04FDB0E52E9 +:1504D700EFC24B09339A731CE3886F2C203A191CE0A344E0591A +:1504EC00183F514DC49F88258C471F213EC2FAAC68A8CFB85650 +:15050100D6535DAAB92A3CE7C0EFCB0728CC6BDC33EBBE3AF4E9 +:15051600E76BC964B19EF8949519FF64CE568E091F74150C995D +:15052B00885B1C83D82FEF43FCD0E167A306513B39C4E31CF4C7 +:150540000131A6FE965F4D26FD9E7387CD79E78E9AE46AAF90F1 +:1505550009FC2A0E7E2562E5D1C8C62AB40BFA87E7CCA98C1F9A +:15056A00E07CDB0F02E0079ED07A136DD5DEE892EB27D74DDAA8 +:15057F009075F0D47A1E222F1BA9F524FAABBC1763C2F6998923 +:15059400F69376FBD1FB4F007E4396CDFA85CD8A1BD166C3B678 +:1505A900CDE268B322323660755A03C6B5E64D2B053DCC1D2390 +:1505BE00D266445F1497ADAD0B68E03E15BF6D6448D8278AEB56 +:1505D300C80678BEF73EB0C30FE947E092E01FC585095735DAFE +:1505E800F671D7EE55CF245C958188AB5ADA037C046D01BEE121 +:1505FD00BAF4A9E9518E9B1D5AC626FE09B121732DAEABB48BBB +:150612008C15B459DAD7B3F32CC428FA34D7B6547ACE7D067369 +:15062700345B4F0631B39A266B102748855D9AEE95FAA9DD5677 +:15063C00D4EA35EAB4875792D2583897B499FE5D3F12FA91FA31 +:15065100A3343AFA18E487C7B823BF7489DC027E87B620FA20D5 +:150666004FD1F043DE9AE5B0C528F877AC664BD58D1BD21EFFFA +:15067B0059BA7B79AD423CD23EFF6EAE509A67B0CF7B609F6360 +:15069000FF23F63989F6D9BCD64CED8550E85072F557D21EB076 +:1506A5004745AD6EE339DB1EF3C922D37F7DA9B0478E5E629653 +:1506BA005AA5D57F827B8FBE9F46125FF04F66E1FE5412866761 +:1506CF0086F945D818ED469ECAF8A08A7BB46860BB6E87ED4EC3 +:1506E400F114BF6CDB45C1764D60BB8F6DDB5D00DB21FF8083E0 +:1506F9007F83CD7B22DFE3C67E6F5F26674C9F2BE638724555DF +:15070E001A0F7DDA111F0B20A778361F4BE710B11F8EC13CAB3F +:15072300CFB85A932B64C35C82792494788F611E51E60E9B4A3C +:1507380007E413987728E1C8273927219F0C603EF1E1B81893A8 +:15074D00F9A4D8B3F9A4F963E02D724A539F88D97980873AFBA5 +:150762001C3A37E59359CE5C33A1781D3BC1DC9B7BCDA235ED12 +:15077700A29E2C523E379B4988CE17BAF7F3909FE8EF821F7925 +:15078C000AB11608D25AE1474B445DF7FC5CCD20E5FB68A3A870 +:1507A100170E70A2DF010DFCFD7FBBF54429CA4C9ABEA016F86E +:1507B6008190DD315E0F7E5103E34F925FAF825A94A30ECFCD41 +:1507CB00EDC7BD45FA3FEA06F6167AA890B7BE6EEB8ED2E275F7 +:1507E0005F9819585F7C7324B932C5ABCC90B5C0CDF0B262939A +:1507F500695544DE16B4F419E647605EC90313E7DD13D9B652B6 +:15080A00AE1BE31B70DDEC7941C02DC8C25D1129B371352AEAA4 +:15081F003D7B5DDD02EF009F3F4EEA549887F684FAAA68452469 +:15083400AF42D45290DF570BFC56BA0BF015C4D73BF911F04B90 +:1508490037E243DE03FC62DCA7D1977CA206EDE5CEFA7063BDC6 +:15085E00A3BEDB4CC197290D617DA68BDC791A7B55055EA967AE +:150873000D7A477DD7EA98BF20E2AE48D57848C3FD00350F601C +:150888007C421EC69849CFB37FEA060FC6604F20B001CE496318 +:15089D00F45BB141FAE3B6A126DC2B99A8E7346641AFCCBD0C5D +:1508B200FC9F80B3D24E383761AD1C83FDE1320F41BEF0EFBA70 +:1508C7005F9C89FC501BE39EAAC2D98AE8F5D48775DE582DD4FD +:1508DC0079C130D653FB649EE04837404E899AD0B2CF592B7220 +:1508F10048F13F47DC707EFA7B13EB3699AF0DFBFCA4DB755C24 +:150906003B75477AA046AD605EF541B3E5D6BBCD36A0A978FFF8 +:15091B00C6DC8B750C9CBB3007DDB2E7553337827B40B7D80387 +:150930008A033190A792DF42FECCF4C379E3167106B1EBAEB1A5 +:150945001EEEC7F307D45D9DA1DE74BD05671CBE429CA18E43BC +:15095A00BE5B682CD0CC95E2ACA1F6C4DD381FFA828EE5E21D9F +:15096F00CF4F17DE36CBDB9B95EA476A72D279D11F53A6CF9FA5 +:150984002F7597077ACCF25BD6C49886A7633517D785EC80E7CC +:15099900C4DF12320AAD0BDA4E683AB425D008B40B301E87C6CB +:1509AE00A0E9625E4FDC6EB04FF43059BBFD16CF2CA13DDE56FB +:1509C30043BEDBB50EF83FC2317F3629F20C3409C7410F71268F +:1509D8008F2F88CBF60A4BF1D9381D5E9ADF82B8362D3FA475C3 +:1509ED00BA4BD293F8E3643ABE8067E39C2533D1CBD03A3C13A1 +:150A02009E8DD33425BF89326D9C964E46A68553D2C9D040BBF7 +:150A17007F55C31A995C3D2CF1C7A25CE40D8CB1E29881790360 +:150A2C00623586F12B629A58F412FA289C3F647C34424C9608E5 +:150A41007F9B2E4E5E8138715DFA8579CB9E939363247D66979D +:150A5600B181F1823501C620C60CC64E3A56ACA39958518FC96B +:150A6B00B3FA18D457D69F1A6B2156F09CCE223913E224153FF3 +:150A80001F431E9A8D7990EDA5175CF2ACFE817D7D38027114D6 +:150A950081380A7D8D38DA6CC751C3639938FA009E23DF07232E +:150AAA004223D0128F43850E8D416B8016825602ED1AE0753D49 +:150ABF0036318EC41D03C412CAEFD9DF938E27E09B965B03B992 +:150AD400F7BCFF8A21C70726C557AA05537E9F8DEBE047317E33 +:150AE900DEEF81F157441D23C75BE2B2C13A3649FEF5022F9BEF +:150AFE004E8B23CE5AE21F91E9F8B54C8AB35E320D3D874FEF6F +:150B13009A915E86969EC69B420F382B230E9D92DF4499668A69 +:150B28008D7A32959D60BE4D7FE194E3683F394E74A0F3154D74 +:150B3D00CE4DE17F988EBFD4BA8B38D4FBB846C8AC542C4EA83B +:150B520027713FDF91D98F156FABA86DB78CB65588BD1DFC5798 +:150B67007D286614EF1AA4BA479E078B77F5D28847D6AE88CF94 +:150B7C00B0C665526784B9B260E38E7DBC445B88674CB6E10A5C +:150B910021EE75DDA61F635A2DC718F12B780796AE33FA999E1D +:150BA60043484524B702756A8067E58101519721BC73FE108595 +:150BBB009862B92AE8AF77F3DBB513DC1D6B73DC635914F1AC84 +:150BD00087F12E56D25A75B3B4622F6768017E1CF67CBF1E338F +:150BE50015C85F985FE2F23B9EE0F375F4B11CFA743964B06EE9 +:150BFA00521FC48BD74A7D2C873E5F492B4B9FC12C7D06BFA10A +:150C0F003E71873E671D32C46F521FC44B7C47EA1377E8F3954C +:150C2400B4B2F419CED267F81BEAA35EC9E8B3E44A460684DF02 +:150C39008C3E88A7DAFAE0F3AA9BA595A5CF48963E230E7D4207 +:150C4E00F6FDA61A180DA77CBCCCA066BB897CA58FE0FB4EFBF0 +:150C63003D6EBF37D8EFC81FDF0DF11EA3C29781C7CE1CD1D360 +:150C780041FBBDDF7E1FB6DF2FD8EF23F6FB6AA0B3533BC6C47E +:150C8D007E0B63EDDA49BC1BE40C9EBBB49FE2F99F8FC273BFE6 +:150CA200F6160B698BA97DE6E61ACC2B857D695E24B73A10CB76 +:150CB700ADF62572AB3DB00E78DE451DCBB597059D7A98BB5EAC +:150CCC003B25E844E1B9567B83E1FC77A41C0C79D66B7B98A408 +:150CE1006BF18540B710724F0D394B4F6F3BB916715096422D36 +:150CF600B702613FD9F653011B75C0F66E7B4BC050A614EC99A4 +:150D0B006DCFAD4DD15FACC9F5433AF3C4733FABB7F9A34C0FC4 +:150D2000960DAC49D14CE122AD146E4A5694ADD4C645BAF768FE +:150D3500B9D5381EB56DAA3D216D1ABA22EF6F904789BD3FE19D +:150D4A00B8BEC3392EF9DD65D358286174F44989B3DEA681BC57 +:150D5F00FD4803C6C69FC88C55D9760CC3F846B01FDA8EC2739B +:150D7400583BC0F0DC392264BA2CE4DCA1BDC88E08FB76F1DBED +:150D8900AF0807F47DF7466E65D9853BCDCDA56F2C7F612C6631 +:150D9E007C7B2DCAD12E6C940F67B9556BDD952B4AF72C6730C3 +:150DB3007697188B0B79F363B915F3DE7257064A0F2CE7305641 +:150DC800B856CA8FF6CA8738B9F17B77E5EFE6BFB8FC208CFDBE +:150DDD0047756E753E9C577F7DF1F32AA4F9F17C5A85F3FFF557 +:150DF200C86015E29EBF78026AAD06C113E48F5BA22F113283A0 +:150E07009E715DF43B056D120CC555D1370A39E07C18C798B8BB +:150E1C00EDCC6553F93002F1F71A2D10DF7F625CCEBBCC6B45C5 +:150E31002F6D4482116E403F67DD5153D9F47DA8B3F6D15B712C +:150E4600AF04BB49BE31DE2AFA06DE2EFA2E61CFBC3D80BFEF5E +:150E5B0069C0BF9B16068280AF895C26F2ADE81BF9B0E8570B92 +:150E70009BCF3A03F81FFE10F037D1D9011DF0435CCA1DE37EDB +:150E8500E89F15EBB093975CC9EC6DA454033C43ACCD23B0367D +:150E9A008DDA7EA606C6007681AE96B6E141D15FE0E5D037AD30 +:150EAF00245E1674D52944A3FBAF277DE84B3B005EA01D83BA29 +:150EC400C112F6CB81B3F8ED77209E8C2BDC2B1FB171D1DE7613 +:150ED900BC517CDE0D3C55EF0766EB9A98FD6DB39F22BF48E2BF +:150EEE0067DCBF6B08EB5F529F789DC33BB340367FA8CF54BDFC +:150F0300782FF021776B43FC9315B63CDA1DF4C69792C76198CC +:150F1800AFDAF2305B1EAA65E4C1BDEEBC8D3BEA9067740679E9 +:150F2D0074873CB5200FBC3336853CB50E799EB4797C807164D6 +:150F4200CB336ACB73BD2C230FEE55F7D9B8E86F2979F0793A72 +:150F570079420E79D6833CF0CE6253C8F3CEF28C3C977E277943 +:150F6C002CBB827B9A940779A03C3B1CF2E05E735AE20A5E2E36 +:150F8100C8ADADD57DFC7A32994CE55867F917D10659443B01F6 +:150F960039BA96AA810DE1CE35FD14FF4FA873ECB821758973F1 +:150FAB00DDCE291BAFE0A505F1791CFB6658EB6539856F9A5A59 +:150FC00002CE58E939FD7C839D8F53B806E04521B67D901B9DD8 +:150FD500F3752DCA6A81BF017218DA61689FB1466D21DBA92DFB +:150FEA00039F2967ED5A15ACD57A56663C627272B07149A28F90 +:150FFF0046ADBEC62EC08F6923AC5FA3ACF3C8095A4C06CC398E +:151014005B8FD0F9173FA3AD5BEFA46DF397D2E7B62EA7CF1F57 +:151029005943DB2FAEA387E69FA6783FF357BFC8C198A6F8BFCB +:15103E00542F1C7993169CE9310F5CDC07F5C0BE554EB9CEDE5D +:1510530043BC85DAFAEA344C6FA1E5F712AFCF09130AB4D0C3DD +:15106800D3C06BAF2527C18D480BC37C89F6F12F9E621E6BA1D1 +:15107D00CBD64C01875AE093F9C4BB30D6C3704D312FD45EC9C3 +:15109200D405E99F3AC2884A995B13DF2FD855FCC78E2063D72D +:1510A70044DFC5AEBB64AD33EE92DF494812EAA2C23E336A0D67 +:1510BC0019F87D638EBBCF3C9433641C0A0D189DB0962F586F8B +:1510D100189E0F3E1777C9F825E280D561A81BA9897E90EF9079 +:1510E6000FCFF76E3A24E0CF440A2A3E49FD7B8D9D377E5E23CE +:1510FB00F7C7487A2F8D31947F01EC63F9B1DF97CF8BFD1DEE8E +:1511100023F65E382CEA18B97F0DCB5C073693FB1FB371BA04B5 +:151125004E43669F14F1F0A4CD6774129F5B27F091FBE5B0A8F2 +:15113A0087527CE2369FF5361F89D345651EEE67B171428E04DB +:15114F0095BABCFD7DA63FB4C83C06BAFA2277560560AFBA7A78 +:1511640043EA7B3E726FC56578F680FDCB0C3807E50E34C29EFD +:1511790055AD94F687550DBF8B04E9D8DB9027624A5DADF6326D +:15118E00DED9F9DCEADDB00F75B0D2D0BEAA0324DA48D43DD4DD +:1511A30055DA15762F851A4DFF0D5FA8FD86BB6C5B57691D3C31 +:1511B800A41DE0FE441F63B97D4DCBB46E8E79C51A053D12BD56 +:1511CD004C059A08276A94C281CBE3E4B9E527DDD5CEF965C6B7 +:1511E2004193DB34702E3E232D1D68B94B97844359F37D303FCA +:1511F700A4BDC8A186B0E747A79CAFFE23EE4D4BC2284B10C611 +:15120C0096419D11D43AC45D3427AD8D86F62B9EAB609E3B411A +:1512210039E96C74475AB90FF66017D6BB7A2FF744A2BC2032BB +:1512360022EE9C27FAF1B0EDC7D6043F4EFBEF689FA13AFCB79B +:15124B00106A85B48F821FE0FAA18FE6ED1F308BC92253EAB616 +:1512600044EA16EAAE76FAB35FEB608188BBD28DE768C2A807ED +:15127500D6A3E94EE2C5F7E7E7B61B259B89F7A5B93143D596FA +:15128A008AB5598FEB0073D9FAE876EC73578BFF21CABF23206C +:15129F0069AAAB3C61159E676A128F885E0BA4E4D620EECA880B +:1512B4005AB8CC6C752DDD9E6BC399CFDA9E1AC7FF6352430BCD +:1512C900BFE74ED10845BFE74B3DAFCBC0459C801EF81D11EF02 +:1512DE00CD0E6AEE3A96DE9BE4BDD916BCABB2EFA5314E08DEDD +:1512F300AFE9C75940AB2EC7B51570BD8F5DAFA95E29EEFB990A +:15130800BCE39FA37799F8BD016922CCA746CDB3C9A47F527EA9 +:15131D00B2F9D74EE2DF6EDF9D4B39EE127766BD71A4A3240E38 +:151332004BBA3A7E4790307C4E4C419FC571FF91F4D500F0620B +:1513470094E2BE68D3F4F9347FD50AADA02264E78D0AEDF66A05 +:15135C00A0C97C6A47FAEE1068B3A2ACF7F4B3CD8F8F1D355654 +:1513710068F757F8B4FBCB03DAA28AD47DEB0A6DBBA46DD35490 +:15138600BC8727D155DE9F19B638717B25D610F8EC4638D8F716 +:15139B00207ECF8950FC3E731ABFE72C4EB82B713D104791385F +:1513B000EC20E660C4D1FB38E2A0ACA501AC11A1B67B88903162 +:1513C5000236FE4BE255C5DD690CCF9BEA79D24FF15ED2F20E35 +:1513DA0088EF6B44AC7B4CE0FBD5D7E47730FBDC81304D1BA0C3 +:1513EF00E28CE280056D58A303B6CC8635E0D9B754F0E33B1C7E +:15140400E3E2FF0C865D648936C09D30DC971766C188CB4DCA55 +:1514190027C2583DF46A6488A910CBABB3C712CAF87016AC0146 +:15142E0060235930F7BF29E3A3593002B0771066AFF37F13F3E9 +:1514430084C1511569F6242F3203617CC0644C280C0F0C1AF656 +:15145800229960D0640871E2A297502C37025AEFB141264ADC60 +:15146D00E0A1CC4156D92DEE7CC144126CB07926122DDD9DB8D3 +:1514820099327844070F14B7425DEE8E73BD2D6A2B6559B7D497 +:151497009D52B355DE15578538BAE8B2559C73DFD7DD6FE6CDD5 +:1514AC006450F1F6EA7E4CBD37DDFDBEEFEBAFBFFEBEAFFBFBA7 +:1514C100BA31DE44D82DB80EE738919E4FBE9AF31B37FF6E8C0B +:1514D600D97D8E4A1BC19FE113CC3500EB7D15DAA8986B25E05C +:1514EB0087B471F62449D02133CEFDA473208FA0ED37A19F74B0 +:151500003663C7C458757D99E6E3144ABE9AA12F947C9BF50CD4 +:151515008CEBAB1D34234CD447180B4298111E57823AA4431D81 +:15152A006768C3D7CAB2AD92C6AD92463FE63CA91C16DF3FF7EC +:15153F00E1FF709CDAB90469291BFD5236446E9DE415D833C0CF +:151554000DBEEBAB6C10E61C105FC6F58DEC875B3ED5BCE799CF +:15156900AF3269B70EFEBE8AB2C2569792B0D97682E72DADE6FD +:15157E00717D5146D64D2F2B7296012DDCE704CDE492EFAB5527 +:15159300511E4ABE0134BEC1CA529CCF7E53D2C1CBC0E6F81BA9 +:1515A800C7A4FE495015BE293361DC608CF8337C825E8FF0D8F6 +:1515BD00B855A83D29D09E64DABF2DF80B65F06EEDC9F843208F +:1515D200770BC03B94FDC477DE271FD06EF709DE2FB9C6F8FCD9 +:1515E70009F8B2F5FBDAB2F576D9D305CA9475D3CB4A9C65796F +:1515FC00F1542EDF728EDAF3DFA91B7AF274033EA764DDD5BE7C +:15161100310B7C63D755E3F3FBD96FD1EE4ECD27B36CBD843CC7 +:1516260079CA9639785F78B6D748E4D5CF3A3766081863B4A142 +:15163B001CFCA948C92615F7A301D6853FCFEA38940F9C17769B +:15165000DD94B30E78E19670F8D301632C0F86CD032183A2CC22 +:15166500CC2F03787BED325FB6CC2C5036D39B5B867DEA73F4B0 +:15167A00D92EEB2D5056EC7596993451A9105621F9436214752A +:15168F0006CE4B1FC83CC6CA306EC2FFFBC7DACB1C6B51524A3A +:1516A400F89A13E5D7C7E5374E6D399F7910F72B13AC1DE6BA33 +:1516B9003F2474592118EA35C380BA700CDFB19DA53BD60968C7 +:1516CE001F501F6E475D02FFF1BB0315633A878FB2E223AC503C +:1516E300B9EA28A7CEF6E585CB5528EF92712E94FB7C7E617C84 +:1516F800B820BF7C85FB3AEB5CC21832C7A3072A123AD703DF1D +:15170D00866F7F4258D8CFAF1B037A2D747D6758B9E39A907AAE +:15172200DEB6FD421FE7F23A571F17A005BE11B48C51FE04D841 +:15173700D7233CF06F0AF2A1407B92699F4BDF1E87DCE1FC7519 +:15174C0079A7CF6FE29D3EBF8BBCD3E7322950B6DF337D7E97A8 +:1517610078A7CF6525AF0CDB3FE7FC36BB26E13ABB92CF716123 +:151776001B90A70B1DB60FE3E0DD72AF86386CA19A57A738EAD9 +:15178B007C79756E475D795E5DA9A36E812AED48204577F72309 +:1517A0005D268F1F667D8F380BDA7BE6DCDF88338C69E058640C +:1517B500FD8D98217C8BDCDC45A266737E547F75BBABAD8E9F57 +:1517CA0067C09C7AF516428A0E361AC9CFD31E5843EA53F054F3 +:1517DF00802798FB87FB643F03997A3EF6C77A726984BDD79F79 +:1517F4008DAFB70EFCFFFECEB7104F0DD0CA423DFAEA3B9555D3 +:1518090076EC09E339A4DB7C7312CFA274C7DE9CE2CF495CDB6C +:15181E00C033F9668A9F5101FFF25EB157E2F039A98B8C9F43E4 +:151833007E52807D39C4E339D2CEF6839D1D053B0BCFEF8FEA65 +:151848008277D59C77B6CD8D7D96F6106FAFCE3E93FC8BB8384D +:15185D00FF50FF35013C13CA3FBC53B903F1EDB957CC93DDF0B5 +:15187200447F12734E79CC08FEAFCFF137E36CCD771C7335E3A0 +:15188700FFA62CEC2BF024217992903C49489E249027C5B09E3B +:15189C00BE16FEE15CF26A4B0233B5BEC04BC58257A2EC562824 +:1518B1003B1018CB295B01654381E3765929969541D98D8149CF +:1518C6002CE3FBEE829F7A0AF8077C6C4D4DE7E3A53B89A721F4 +:1518DB00857CACBAE34FDD9FFE02F25024E5610FE03DDF9C4B45 +:1518F0006783423C473F853903B4BEF4E9745A5BE11BFA29D2CB +:151905005AF3AD69B5E391DF86DEED05E82D96F49E015A1B9ABF +:15191A00A7CBAF8939BE0564F7E38B694F11F4E3838BD3FB616C +:15192F00029CD317B11FBE6BEA47E63CEEB7EC4F5781FE28B23F +:151944003F5756114F17FCBE0BFEF73E813E69554CD56A18D73C +:15195900FDA0F35CCB09998472FCAF9056FA21BE0774AA017723 +:15196E00166886A56A2D2F22FE08E899B511DC0F8C51DC35426B +:151983009B98A262AD12DB0FB65831C11EF6F3FD2C0AEDCE4436 +:151998008E58A51DC7ACB512762F3CD3D79B74233C5DE2BFBBA6 +:1519AD00218F9E06D95687E746F0357D9AC04774810FF120BED8 +:1519C200E833B9F81640BBD28E23D65AC0F7E10501C327F17D8A +:1519D7007C41E083FF6E273F55C9CFA34D44D437919CFA39B6C6 +:1519EC00FE93F59756E6D6CF95F5DB65FD0779F5F364FD5A59A5 +:151A01007F9CD7A7A8EFD9ECF9A334F491913E1DF790DC68A32C +:151A1600F3CE1BF5833FC4F0CC47656C7333EE2F997D75959A13 +:151A2B0012D4A53E1BA838AF3787F6055B1DF1DCBD273B7E8D0B +:151A4000BC7ABCFBFDE680A3FCDC0BCF5CC1F2959B7FDDEC8CD9 +:151A5500FF9E7DEBA72F63F983FFF8AB665289B1C761DAFBDB56 +:151A6A00275A7C7E7373EC87C433761FF14CA3D391AF9B7A36C9 +:151A7F00D73E0B5F2365A10E7179C53A8C97A9B97DB3FD236C72 +:151A94003713647D3028721BB0ED40DBB83E33725F607F1BD7AA +:151AA900E5CCB47539D4719D0F3079591E3C5C6F52B02D5D5C15 +:151ABE0086ED35183306CD2A1DF7BDC16FF4F457C4F4BBC89216 +:151AD300A0972CA99BAFB98298233650C1F4756655F0BD0C5F2F +:151AE800C6F83EC46CCE0FB6177D9412F0F546F3EA3D8E7A059E +:151AFD00EA7BB37CED2F5248BF1BEA5DB5307EB2CD7C6ECFC40A +:151B1200B7D741FB8DB2FDF740FFFBB592805DE787BA0622E42F +:151B270009FF2F3C3B6254C3FFF98E360BCFC60D5F1E3DF7C0A8 +:151B3C0038252271CB0DBAB6FECBB4277625EDD9FA557A96EC0C +:151B5100DFAA49D0D3203F397AC527E574B491F079134A3E4B1F +:151B660093256416CA19FAC136EC27619E610C4775D0E5AA8842 +:151B7B0019C723DCFED2808C3FEF01B8D5C0FFDE45C493AA12E9 +:151B9000B27FB20160CB7D72226DF99364980E4E8EEA336F4273 +:151BA5009B1EA0C297D5E43E6D35C576459EB8F1AF8B7E50EF22 +:151BBA006B8CB1062BEB6F45E0BD669090283C1B9E23C484E70C +:151BCF0065F895C3FB65F885E0C79E13FB5D08A7F53FD29ED399 +:151BE400B82693FFDDE7D39EE3F89F8DB079303E181BA8E47B6F +:151BF9000929EBF4FD843C87B6818D58367FED75C669919FC22E +:151C0E0061281AC6285EC77C7A9ABA8F102FEA228C9B711FF33D +:151C230088E56AA306EE2763EC8AE7CAAB23B8B75AD6E4A0E3B9 +:151C3800AC9BCCC2D82AE2C7734FB857B100EAC73CD25E713CCB +:151C4D000798CA7535A326FC5FF05F609F501F89FC8B0C2D99AC +:151C6200B39958F63B570AF0F17D3CC5F18E7B97F63BEE59F2DD +:151C7700B80FFC1F73C4B96C783E76C4405D904A5FCFE71EC6BA +:151C8C004486FEF9282F23A9EB89EFDD51F10E7F701CB36D6341 +:151CA10016C65186268FEA650ADF43B1447C2566613CA5C94103 +:151CB600B7D8BF1CA60F4C3D30B5787234472E67A35C227D20D4 +:151CCB009BBB6F271E1EAF0C1F61E8F7EDD7560510861B73A2DD +:151CE00022A798163941FDFC9CD3179697E700279862EF075FF5 +:151CF50014F916FC5C82DAC3F74C791C397CCC7A5CCEC76BF51C +:151D0A00279B1CFCFA661A246E3CAB84F80BCC81F25560EBE5AC +:151D1F00FC60B8F7AC522E5764B288801D328662CA263C7B40E5 +:151D3400EFE5716FBFBD6E9B43460CD46BC85B2AE9C3EFCFDEF8 +:151D4900463CCAD45386FAFE53BA5347E2792466821EE76BBC5A +:151D5E007E9AFEBBD30AC626152EFBA6581F4D017FCCB87E3379 +:151D7300190DE299C5D496A3CDCE71B94EEA8BEE159C0779F150 +:151D8800175CBFD9704D0E374D4ED2CC99447594611CED7B66CF +:151D9D00BC20EC191276F90A92B38F9B858F79A4FD745FC5B0E0 +:151DB200CECFC7838E45FA63FCEC42DC5C8CEB03C0519C1C3729 +:151DC70095E409D35D1A37704F7026E09B1B66862B42E9A1A492 +:151DDC00B249D17AE90DEA2F8D33E9B4DF1B5382D9757098A279 +:151DF1005FBBDB85BAB015CAAAF9790D9EAE8B3EC3FD620D515C +:151E06008ECFCA06983B77BFC8D75A01ED4D727F017AC13E46AC +:151E1B000EA37D1CE6F6715FC549DD3BD9773BC737A5F4B2C6FC +:151E300031417B386E7AD1DF93E54591B8A9362678FF0E9103BC +:151E4500BA05F2EA5E07F38DC5AD9BC51955E68A8C67FA3737FD +:151E5A00341AB4BF15FA2AF33E8D9EF70E67F371F7817FE13540 +:151E6F00253DEC2AF440B90AFA176971E2748978EADE9C3334E2 +:151E8400A82741C648E549B18F20FD33E09DE08FC82DC8E5A33C +:151E9900DAF762CE7E3DCCBDC806EC036BC7791A4A1EDE5B29A3 +:151EAE00D681E683503E188EE96EAFD86B4B024DE78B4D3CA3AA +:151EC3003E0BEB03EB458E0CDAB0C572EDD8CA6564CCAC833ABB +:151ED8009B764E37B46F58CFFD6C1EC75F2BDB353ADAB5245FE1 +:151EED00DD0B3F13CBA3EB798CC4C43831F605D7AA48C7E05399 +:151F020071DD3729F704A1DCC6DB25E1FD5501BCBB1D78B7CB1C +:151F1700763F71B4BB0BF0623BD3D12E2ADBF514A0EFAEE41B6C +:151F2C0026CEB17E4EE3DF9B685FDC408B0AF43DCF65679CEF03 +:151F4100430FFE13D04AC4397EB783D66E097BA000ADCC41C374 +:151F56006ED9EE50015A871DEDF6C8762F7C0DAD38C636ADA5E6 +:151F6B00DF406BA983D6A484DDB1613AAD5D1BB2347C2CDB6D89 +:151F8000DB7095F1DC901D4FE52AE3A938F09EB7C7B300DEDD56 +:151F95000EBC17ECF1BC0ADED68D38BF2690074C75E2C5FECA8E +:151FAA00FB36B0DC96F935D0FE308967647E638990F92B2E21E2 +:151FBF00F3A18D59DCE11281BB65E3D7E006BC3E89D7C6E77309 +:151FD400F473A384D1561806C3396BEF7597E7EB3CD02FC75F90 +:151FE900CAEA3B3E9FF95D0A4719B767784F8E7A9CA11FE92EF7 +:151FFE00ED33F6815FAA826D53D79E32CAE909E32021739C3A1C +:15201300E86FA05F85748FFD9DDF15D70F9BE33ACA8B88271E8C +:15202800D0613DBC17D7BF77715859DBB01C6015815DC8E8D5B4 +:15203D00D0B8EE5E17E73A95EB53DB5E98A84FE35C9FAA6D40B2 +:152052003FE85197E33DA7BF9598AF31ACBB2A9881E7F178AE2F +:152067008CB0F9D23625047E26F5697848F8946063455F46F90A +:15207C00F9097E3E08ED52641CECD23B863B7682A26D2A684F28 +:152091005ECEAE1F193FC7D46BF8319C8E7B15F2FFA5747A5E1E +:1520A600FE5A52EC77F278BD359C02FDEA81B915AEA12CD41386 +:1520BB00455DEC2E163A59917E7C293CA37F486772FF588AE7B0 +:1520D000E79539F3C6944671EF4CABA31D5EF893DF0E6DC2F3A4 +:1520E5001A9E5B3AC910CE83987F510BFF8167E877BB2A13EDD1 +:1520FA00587F4368D4B821F40ECA8CD5CC7345C618C2C372FF1D +:15210F00E6B895FDFF8EC1CBFE3A8E3E0BF1B38421BE7F076D69 +:15212400BAAFC8DB631CFF324BD3608AFB4D0E9A12B4991C5B1C +:15213900E9D75C011B37DEBDC3F34230FF1ADAFB6FFCC2CABCBE +:15214E00AFFA228327B9F058535126EF07D6AB320F1BE92ABB9B +:15216300310E7EFE10B3F819D31A3A07F87D3BB24315B044DB21 +:152178003186FC07B368A9EAD330D6C7E19B414BD18E5BED0E8D +:15218D00BF12D6DDE411AD64E5844BAE8B0BE05983BE4B41D8DD +:1521A200555689FA16C09EA0840D594AEC94856704C4797E691E +:1521B700BB51BF15CBF98B396DF25C0091759305FD19915B88C8 +:1521CC0072746106D29560ED226798B9257D6E271D682B8B05AC +:1521E1005C7F30415522CF2AA8C72CA443FD6889C56D51868E26 +:1521F60014ED8A65E51BE11CBD4FC0194C09F8026E82F3A7EC3D +:15220B00A33EE68235223F8347C6753C138F3EB0F82661619B93 +:152220009C7900F03F8C65FD1FBBDF083F719FE89FC0339683D4 +:15223500C7DE73C0B69C8F49C1C71B36F75AFE7082D7259C38A8 +:15224A0033E7914354D0D24055CE975679875080BA653E202FCF +:15225F000F8FB28717A1EFFA0ACF4773D2E07B7909738E1DB4DE +:15227400B114F508C6FE992D27E80BE30D65CF935E9DDFD31477 +:15228900A69C2FFCAC05D42BD05FD660525C841797F61AECC022 +:15229E00ADC607FF96F690A911BEBEF7E118A96F1A8A768AF9BB +:1522B30023E24E017B0D535E3C7D1DD5D37624735E3EB39E9A77 +:1522C8003A66DD7EADEBA9F06B962D539847365C22D6BDB93243 +:1522DD002564086919967CE163128C7179E2EB5958C7A33D4393 +:1522F200794219E0BC32C51AFEA5AF44AE52A1F504CF1B0EC06E +:15230700DC6717E83C7FA01DF767BCDA92FAF7D19EC23AFC1118 +:15231C00EDD6E0659893CB93BE55DC36DE2FF37DEEC74B4F0E1C +:1523310070B9E3F960A2DCC2F2F7E4FA3622DB46F3DACA720B9E +:15234600CBEDF3B836FC5EF9CD60DE37B2DCC2F22E09BF5FB607 +:15235B008DE5B595E51696DBEBD4C512FE6AD916DBE1FB028718 +:15237000BE6975D4E13B9E6DC2334D6E90A362B0558A36622134 +:15238500BF1475BF81E31DD046F19EA9B9734343CD0AAC57CB16 +:15239A007A2E18A5DA116BBEF94993BFE55343891CB75E8E95C9 +:1523AF006C72C39A0BECF1BC9991192B95C805CB96D999A0DB1C +:1523C4009257709F2E3B077E0A3652E1E746D8B4F928E757464D +:1523D900AF200CF5E08831583CAA236D73375759F67CE632C014 +:1523EE00CFE58EF3BB8BF8592FA147ACFCF92CF2400127CC19EB +:15240300E73C796A76AF91F8ADD84754A54EFBA679F27480DF1E +:152418008D23E6C8C008CF89518BB3F98F8B31F7007C8D07F85F +:15242D00DE7E36AEB50EE4CD67CBCDFF36BEE9984FAD45FF072C +:152442003A3ACF9F086B23ACC4DBC7F9F912C06BFAD4E10B5CB6 +:15245700CCB3BB400BB611FB20A6C5F7472AC7DA4B0EC68D21C8 +:15246C009015B5294E93220662B9C57E29BF37096D33D66BB0B8 +:152481006E4FA17D97F0307EAB4716B1622FDE75D743272F66C3 +:1524960071AB05FC107704F0F23D0AD3C2F11A02BBAF4E8CD0AA +:1524AB00CB12278E6F0E4EA877E7E1CCED7F75FB4607FE900352 +:1524C000BF5600BFE2C0BFA000FEAA6BC48FFE456F6380DAB4A9 +:1524D500200D139F081A1600AE7CFCEAC4118E4B8B8CC0DA3C30 +:1524EA00D10E6B6F0B7D1F45E377CACC5B101961CF83DF833679 +:1524FF00ED92D3CFC1589F5A65F5B65103EF74BBF46455338FA4 +:152514002756DFB4B4AA6D6B50FB6143E366ED9EBF587FB7B6A6 +:15252900E127BBBA3B1FDDA5ADEFDCDED9B1AB33A8B56CB9679D +:15253E00C7CECE8D5D3B7EFCA3AEEE2DF5CB6E5B16D0AA1FD909 +:15255300D5B56DE7CE1D8F6DE978BC235457D75877DBD23F5BD6 +:15256800AE3DBC6D7BE72E2DD0585BD750DB7807BC04EB03C11A +:15257D00FADBB4AA4CFCCCC6575BBBB533BAA3BBF6A11D8F4646 +:152592006B3BB67644773D51FB68C7B6C76A77ED7CA8B6735700 +:1525A700B4F6E1276A3B3AB6F3B2ED3B764497EDBAA96E857601 +:1525BC00ABD6B9755BB7B6B5F3E18E1F6FEFD61EEAEA78EC478C +:1525D1009D5AF5EEEECEDDDD4B11CBB783BF75E7B6C73B77D624 +:1525E6003E0CDDDAD2D1FDE896AD3B1F5FF6D04D2B1AAE063F10 +:1525FB00039E9F6799E30FB7EFC77D42B58ACEF537B4576BF5C9 +:152610006C199EE5B1F3F423CACA85FA05E350E870B4880CD334 +:15262500F63FA63379FAEDDABDD67FFECEB552517F6054692D59 +:15263A00B40AE6DE39D0253E78BE85BA539ECBEEFA22ED797785 +:15264F009112DCA81D613550379F8C3787B401C6EBC3CAD30165 +:1526640028437DD3E428C3762AD8408069F56BA5AB6C9B500E21 +:15267900BA710611BE04FEBF02B0F7A9CF44D14F1CFE657A16F7 +:15268E00D2E5CC6B77E6B4C72E8B585C1F6F5F4DBBA03D513FA2 +:1526A300B77CF0CD04E68D39F0B328E1676797B9C85CA40FE9F8 +:1526B800F069C718F66106AC53317F8E4C2DC538ACCFDF72AB4E +:1526CD00817DC77B164BFEA1D1C02B54AA0096D8AF3A44C3DAC6 +:1526E2000BB4FE6DC00DFE940FBEB7F1E0391EBCB301CA2C2721 +:1526F700CE35E934C7C9EF6D04FFEA783A3DA732E2127B6AE153 +:15270C00017A1DD80584997C0BF3660350F60AA7AB04ECE521AB +:152721007E6FC47EDC972BB3C7CD3E6311FB038EDDE77CEC30F5 +:152736007EA36930EFD4BE845B5B6195B41C85F13EC061E33C5F +:15274B00C43958AABD6CD57CE56ACAFAAB620C6C7E3BC7C1F730 +:152760004EDAFD75F5574EA66739C703E951811E9F63BCA211D6 +:15277500378D257F65A920875A722431D7BF1BDA76515F7211DD +:15278A009B9D2CDEB43AB914E435DA8E776AE01D89782F0E0997 +:15279F00DF4DDF55709DA453F465947F79D0C07B36D662FC4621 +:1527B400C533BB61EE8B0E9ACBF5D74275ABD66845ABDE2F396E +:1527C9004FFDA15BF83E63EFEBE959975C765ED6009B9133FE04 +:1527DE006B29DE5D89EDDAA1DD19D92E906C01B8ADD66A11DF97 +:1527F30048F03B29E5B326B2860EF0BC9145D485F77F014FC4CC +:152808009D94B9CFBD2E71278EB8E76B047CE95AFD52B180EFB5 +:15281D00A523C603DAECE05C6D76DDEB8BCA82D6E21B83A7B1E3 +:152832000EE3BAE3E9598B355790D3A90E50DC8376C3BC3C0DA3 +:15284700F320137F9B7A45D8E7A957AC9F5754EB7CBF1874E630 +:15285C00A0840FDFF3BDD47E8065B7B5DB6D873607DBF0BEB4B9 +:1528710012DE07DCDFCDC7A57F21E6512B7CCFE358324E77F2F6 +:1528860028C233D982D251C3F7DF87190A4E6B12CF389FE7E720 +:15289B00A9ACD0ABFA10C09D5F5A632C07BEE2D9D81A729EF631 +:1528B00086DE88624C2D896B83B6A5860563751DC84EC99E710C +:1528C5008AB90441DCFF507F21C646CE65F4A915BE2ED380AECD +:1528DA00503BA75FFD85357129ED395A24FA79178C75538131D3 +:1528EF00857575597E9F7A2FA5790E09C2D92EBF9F0F73AE6456 +:15290400CA34F0BEBA2258A784928729FD4DDA637F8B730575F3 +:15291900E284E43BC66F911701E083DD6618EAF83B7B864652D2 +:15292E006911EF8436A54773798F325888569CC7E5C91EE6FB92 +:152943004CF0FC83BFCDFD6E02F98F72CE75C37E6AF37A1078EE +:15295800DD9A1CB1265E933E80B3DFB83724FB4D7F2FFA8D63CC +:15296D008FF0A200AF468E1997CD51219B788ED6D576B71186B2 +:15298200FA9B6DF9936321F89885D1F07B416B1464E2E3D78499 +:152997004CCC2FAD37FC23AEA02D1B78CC3B2AE2B952364EE849 +:1529AC00E8DF2D262756A15CF81A135C1E2C73B1EE1E386228C5 +:1529C100A073174B3910FB02B9E37E12F8EC575F0199EFA15EF8 +:1529D600900B5F4F9D91BA28F96DCF07C737181B2FC4EF6538A7 +:1529EB00DFA13DE7793E1E984F9837649F7FB9CE211BDD201B4B +:152A0000D13342365C781796940DCC8343DEF01C07CCEB782D44 +:152A15003B7E086F76B8CBD0FFFD2FEB41C759D5C936AB2AD9BA +:152A2A0062819EB3400FB202F909FC5E665CEF946A553CC61AE4 +:152A3F002BB00F06FA9BCEF00E1891728C1B8DB5A3DFE6F28C47 +:152A540018B89FA6CB73D6E8833FC0F79712FCAC18DFFF8275A5 +:152A69003B9E0FFB79C54958ABC6F95E981AEBB3300F7275EC6C +:152A7E0014F7FFCC581C65729EAAF559ABB553168367191B3372 +:152A93004E6BA29E2C8AD38FAFE21FBAC984E723A5B9F8B1A2B3 +:152AA800CF5D3F73FD4F7B4F1B1DC575DD9BD5AC342B0D627676 +:152ABD00D95D495848232C12C9519C5DB1C8922CC242A88FEC13 +:152AD20010654B9D744612F63AB603B19D84B634C7E784C42B00 +:152AE7005889058FF03015F65A266695480E6E209539909014D9 +:152AFC0092A5761C9152B2E1381C9AA4F638716C9AB8B6EC6293 +:152B110087A436DB7BEFCCAC56027F25ED39FDD13367CECCFB72 +:152B2600BEEFDEF7EEBBEFBDFBEEBB95BB86F37317D82FD98F5D +:152B3B00D9F7D9636C823DC40CB69D6D619BD917D84676275BBC +:152B5000CF6E6537B33EA6B04FB0B5ECE3EC63ECA3AC9B5DC784 +:152B650056B3556C255BC196C38CB29375B076D6C696B1085B45 +:152B7A00CA5A599885D887D8D5EC83AC059E0FB0AB58333C4D64 +:152B8F00ECFDF0BC8F2D81A7119E2BE1590C4F033C323CF5F4B3 +:152BA400D4C1B3889E5A7AAEA067A1FDD4D0536D3F558527687B +:152BB9003F81C2E32F7A16143DBE598F77CE235DF2CCBFE4A91D +:152BCE00BCEC33EF2D1FF16D9F8A777CCADFF5E379C747C0C3D7 +:152BE300535AF6BB963D6099CEB280EC52D7DE1F63F241F46BAC +:152BF800043FDDFE6F82FF9CFDDF02FF1207FFC863EA9A207EDC +:152C0D0054D359B7968349B2C4299A242F3E28C5E1CDC06B2E5B +:152C22003E487602C97E6C13D9BE9365DBCF63FB71E017B7FD26 +:152C3700CA6D3F17F8656CBF0ADBAF04FC303F2893CE264A2C4B +:152C4C0016B2F342BDE2909D07EA1187ECB4A8371C8234310E91 +:152C6100F768656DE3B751D0BA4A83D9F6A81BE41AF48BD1B952 +:152C7600FFB0EECB70ADC25433F081865161AA83EC1B26DE2674 +:152C8B006CF26DC2C81E0B84554218F81BE8CF9FE850A9EC5CF1 +:152CA000B3E1E0CEC139D62367C3983B4234D1659A8787749C89 +:152CB500F731AC27A509F5237E118792CB8A3F99B5C3813776CE +:152CCA00C98B0DDDC9E7B8E51F837831E49BD262831740067A12 +:152CDF008B6F8C9B89932BFA975C33FFBAED4FF8CFE6E7A36DBF +:152CF40009EB3CB7AC4D93FD5BD9D2E720DD4999743D4AED7F28 +:152D09003A37EB82B686F66043EDC03B5D2CE96A37CA609ECA75 +:152D1E00473BD4E9860E5A9F9BFEBE7B19E204DDB8469A857495 +:152D3300226B471D6CA30570018C5613E456A38C5D05B05F65E1 +:152D4800B883D1FEDC65FC24CEF263F2AB06F2DAA6B96B14217A +:152D5D0059273F6CDFF0BD49E65A79A099941868E571BE2C35E6 +:152D7200A03D4A18CFC35064BBDE42EB5061834908974CB0C425 +:152D87005CD55046B38EE5F353D5AA94688EE0574834B7E23778 +:152D9C008675CD8548A6C6B8D48ED15E6528A425A84FB46B511B +:152DB100D26D8AA27F3C3FBF1BE2C4C88E24CAD0D659D8B8163F +:152DC600A573001BAC33B1A18D961E14BBDBBE272065EB48E02C +:152DDB003AEF7C002A09F397A4AEB3A482FB3DE87E7505BF8CF3 +:152DF000E5B6E8A2CCB7B2D856FD3CD62B27EB96DD5C4B6FAAC7 +:152E0500C52C69A53C213F5A57C2FFD8889EAA49281CD9F31C8E +:152E1A00310A7A20B11FA4B17EB5F2FD3A2F9F30989E84791408 +:152E2F00BFEC9B377F13F27F328DFEE8D7027EA373FCAAC16F26 +:152E4400688EDFA6150097F47CFA7337BF1006815913E5A7F5FB +:152E5900BBD99456BBF205B5B7FE99F043EDE7ECB316093A3FF3 +:152E6E00BC287106EF0EA075B3452B4FA97C665C77C1B828CBA6 +:152E8300DF4A33FDBC21A44668AE836B6D4276775B10E7515087 +:152E98000ED3BF615CC1BDA0221ECAD933E1C99B5F6A031880EB +:152EAD00A64F035CA7744EDBA93EB4EE79ED8AA806ED68A70154 +:152EC200384B5C5CB13A2C6C87F2625B27D9BE52B42D3E2908A7 +:152ED70068EB74DBA8D0FD02F83F306AB9BF6EBBBF3D3A95CFC1 +:152EEC00073217E75CF311FB693AE99AD2116F77B3AC96F85E05 +:152F010069EB97BF5CDA8AFA10A3B9879485A71F504A4E3DA5BB +:152F16005EC7CE8417668FA964672DA4DB76067354D780F4F77E +:152F2B00EAF95B9E3616724F42F81943481C68C3392CE63D7D7E +:152F4000CB295DC894B61EBAA77419CA26C447A4B18349570694 +:152F5500E87C58C7BAFC61EF6024781CF2967EAD617D24843B52 +:152F6A00F6F8A4807B23D2B68312C1FFC383CF431F2C978753B1 +:152F7F0068DBBA4C1E4CEC4A680AD7A3411FFDA98E3657E38FD5 +:152F940031769F80FB095A6ABAE13503E2EE78496E591683F8DE +:152FA9009BE3AB5B518EA1BE251DD0F9CC578047BA5BE3D9FD8E +:152FBE00AD4C3FAC4F63DB8370EC3F6BC19FCF1C80F63348B612 +:152FD300299A6CDB31D4D7F461B20BDF44FD0C64DBCC30F4B3E3 +:152FE80084C6036D25A645F02B30AD15BFB85F266476431E596D +:152FFD00B2C55A9D49EA9C00380A65C9862AB643EC1FFBA6308D +:153012006CDC88A1CC9D491A572534F2CF803FBA512E9C6ED029 +:153027007431CEB77A4176C47E32DD306E2C0C66FA8F5E742F22 +:15303C00035C1A536FE40509E0E98232CE60BF0AA5B52CF0E088 +:153051002EC89765F6184F15CEF7A47411301002E09E1FD42243 +:153066004C3F9EA67929F0B3EDD153CAE9DB4B5BD36C504927FD +:15307B00762B171BF965E9E8B052951C51776DD5945D1D6749C3 +:15309000B694CCFBD39D4BEAAEA13DA3506212D762BD8B92B8B7 +:1530A50027A8D766A84ED69AB680F67513B466DDCEA32CFDBCA3 +:1530BA00CE75A38EE113C6AEACA6E07AA190D903E9B6219E69A5 +:1530CF006FAFDABCDFA8351F369A0037B550D75C298805108ECA +:1530E400FDB349DE46B63C280F49439B4E42B57C9F4E36F7D6B9 +:1530F900691AA4D39137F0F1437AC4FC1EC4DD66A00D4E616AB7 +:15310E008F8A79BA4E4E908E5AEC71C66A70BF3F74846C05F0F8 +:153123003D432AD469D4D5B3534D95B1D9FD23876BFB29ED8BE7 +:15313800FFC6FFF0618EE8427B1E7EF311D203A45B7670CD1FF4 +:15314D00FD5892F4B5B0CED6FE478AF63F8CEC88526D0EA543D0 +:15316200E6231969A5A60AD76B6AC91A4DE565CD1005DCD3DEE3 +:15317700A3354577B7E1B9B1C000B41F98B75627D07DD808DA47 +:15318C006E3CD36EF1FDDD86DF145BD18FEC8D16F643D2B4E610 +:1531A100EF42DCE446F446A28375C69963FB34D4CBB6CE365B69 +:1531B6007720FC02F2E2D6A0CE5E86E8C7A50EA8C14583C60317 +:1531CB0051EB5C2CAE9DBB7A2CDBCB3716D921E03EAA912D62AA +:1531E0000969AB7FED20D93284FAE33A346F022FCB9D277C7B31 +:1531F5004DBE57A4B9439AF6195CA46B6ADDB101F35C03ED4235 +:15320A0021BC9CF945ADC95C102EE6F1C8DB918EC4DF0BBC1DC8 +:15321F00F8FC86D25EBFF9BA4176DBFE11DBE190B1E5CD7CA012 +:15323400E54DECBB162D10D77E73A7EED246546FA7B5D7EF02FD +:153249001E81F7CB886C64A9086D65211B09231DB5A236AA591F +:15325E00F4D2D3A4F375AE9FDA18D00FDD3CB3F45F5336DD9182 +:15327300CE9806DD48D7B934251AD8F478271CBF5B5AFD4FD299 +:15328800A29C6891B6F7796668F28EB4281A6B1D3AE8DF477B45 +:15329D005995A1629AF8E2EF0F93DDEDD8C0E4857BDEDF26C538 +:1532B200CB605C1DD0D1B636F2AECD5F2C6D9DFA2F871F59FCB0 +:1532C700A31A68E65BA4191CF04DA421D6D5DAF3B1CAC0F230DC +:1532DC00EFC2B9A882BC64D1A5A688269B099E94657705C27175 +:1532F1005F5132771A9C9CA4F6846EA5C8BE40A4287DE4930561 +:153306007D5FD2134EB309D2DB6C42DA0F4C28A2EC26DE1C225F +:15331B003D404DAF895ABCA8D00FA1CEDC061C8FE17BFD29C2BE +:1533300001F45B7FEA0F567DCD39D76CA18DFBEA60AABF06645E +:153345000199650E8658F660949907AB7F9BF7C07712DC93E0AA +:15335A003FD96DA77FABF8CAB9D9F1ABEDF838AEEF7FBDA84C2E +:15336F00D4C780F947715AB2CF45771668FAC57BF8655DB87E3E +:153384002E1F4DDC37754C2985E9062F8FA4D04E49B9FC448ADD +:15339900EC86D37E5096CE544AF22198B72475D15CD27AE3FDB6 +:1533AE00790FE2417B30EF999B67316CA4770869BBE407F5F373 +:1533C300CF6A2023E96403C56A877F6750DBB56CAD4CEF0279DE +:1533D800B115E4A2F7D236A79F1DD193AE94CEF6F1BDD3CF6A0E +:1533ED0046D29536BAE45DC6EB17B17F24ECB9C980F11CCA42CA +:15340200407FDC5F95A18C629C5C787A363E717FD796672D5DEB +:15341700687D8F8EB23307FD0BEB086E63F5DF82BC188A914D54 +:15342C0074279FEC8F67F2697C2D2FD4E2D9A16035C8F103FAC1 +:153441004928F36E16D798194AE3BA986836E9A5C7C3EAB7121E +:15345600CDE1C1F6F659B26519C375E276EAF765DCADC067AE49 +:15346B00D765339666D22B862034A8B8D66CC9958BDBCA61EE8B +:15348000E2AA53A80CB4878769DC0361B5321A8E944399FBEB54 +:15349500AF6DAB3565181B9BF46A33A47362A73AF895B0E6CE17 +:1534AA00C23C31D76E387788A0EE07B374D041DE6C0CF3B8563E +:1534BF001DFBD424D36F191552B87FF857F43557B896CDACFF5A +:1534D40057DB7A174D363F0B013F6B5750AEF7C95C88E62A504F +:1534E9000FDEB11D937B64B226BB47ADB1EF6FF0C3388DE3317F +:1534FE00CB7DC7F072CFA9AD0D95D7B0BAA97EC6CE6912FB759A +:153513009B9F7B59DD29BB5B51560C01AFACE526D440F048BF54 +:1535280010FDF5D25AF8BA4EED26BBF4C827AB56A26EC011FBD2 +:15353D00BEA1843605E3BE2F7158F5D682DC52B0CFFCCE6F157A +:15355200C8E6F84DAF288BF8E2653067F98ECECC470E8E83CCE6 +:15356700556BDEAF23EFC276817BD85E18AF9FAA19591A05598C +:15357C0007C7A14FB875926FFEE9412DECC8346FBC997F4B99EA +:1535910026FDFBFC5BCA34ED6F25D3C45ED04CE77C39F21CC0B6 +:1535A60095D0707B5B39E93423DE8EB5F98FFF07E47F4C5B0B28 +:1535BB00B87BA05D776C76109E828943053C05CD2561E11CEEF2 +:1535D000296D99E44F1C437E1D5C68CE0B835BF79901FA969B53 +:1535E5008BE8AB035FBF5CFD619C8DB8BA5F564F5EC80B880779 +:1535FA00AC6B8B5D7766D7BDF63275C734E90BEFBDFE8B80EE1D +:15360F00D5C85763BBD2B1D7E7CC6FA08E747744113D5B8AE3A5 +:15362400C476EB37B0B47623C8F0CF3F35B254968F4F0297D654 +:153639007C1C8CB7D219C36FB74B1EF505A49F1B77B3B39A97FE +:15364E007B91EE4FB862E5CB6A28FBBDC8151D163EAF602F502E +:15366300DBC3FE7A05CE67426709A7D8E6703D17D784EB4C771E +:15367800AB13A7EAF8D305BC57415A491E48272A92BD18F72EE4 +:15368D005CB28D1D4AA32E4AC9D4310C1B759D3CA6EA799847E0 +:1536A2004178937C7B1B7E119EF32BCA966DBAF91990177FAEFD +:1536B7000BF263A32DF2BF1AD5E7ED3AC6862645D437CBACD512 +:1536CC00AC7F9C4B0D4D9E5B61A53F0278F3DB795D58B1BEED6D +:1536E1006AF6F5569A0B15C5C5B49847713AB4F7BEE5DE334AFE +:1536F60048FECBA5E88FE32588D21FC7FF0771CC8C0D65503E7B +:15370B00C5B4E5A8630FB8C4F361B5BBBE4A785D28838C60E796 +:153720005F39EBBF2AECB2FED3E5F2FC307C7557A525B763FE8C +:15373500AE8777A83437FA21F00A90BB8CE8238A144DAAD5302F +:15374A0096D079BD7761A31F5F1863525C6AAD8AFB984CDA4A08 +:15375F00E3901480F1C41E87684CC2B0F7301E3963913D2E5D94 +:15377400763CC2B108C7A408D9F4288C291A3B618D29563932C9 +:15378900AB965F3116A06C01E394206F37BA5FCD0BE5192D5589 +:15379E000E7047A2C956677E580DE31AC6697AD5A1F7A05EDB5A +:1537B3006ACD2B733FA0701DC343801F4CCF32CFE97417484EF5 +:1537C8008379654A2BCD24133E2847CA1C4A639F2B318F699847 +:1537DD0027B6356C734DF2B3A3D8A6CEBEE1C86B36CC00EBA1A5 +:1537F2005D5F813E3CA0D37959B439FA5D6B5CDDF3CA4CFFF2E4 +:1538070006ADF32F82BD5F3659C53C208B7AF62DB0DC719E794D +:15381C0036BB98670A5E4BCE6EB27993A523E2C6BB03FCCE58AA +:1538310098D136039EFCC73BD45520CFBA07C6D491DC98522753 +:15384600BB3B17CA1FFC30AE9D511AA9592D9C178D3540BBE016 +:15385B0086F87883EE96701D8E1B7A716F73849D1FD0CC1378F1 +:15387000B9D15C797276F9AB12CD4BFFA4722ED1BF09F53756D0 +:15388500B10A495AACA2BE2DEE75476A58855BFA06E9475E9528 +:15389A0079B30B75A7825F0AA3AC4B3A51645F00CFE5423CA71A +:1538AF003CF4EF02F78CCD6E9AEB94E3BEF81341B47DD3D4FF48 +:1538C4004610F36D253D9F5C35AB10E363C05797A8EF93B98E87 +:1538D90052482FC61B8C0BE0CF7F6940B7F412F921679DC02DFA +:1538EE006D517F0161685F6F04E340BD704F4F46DD29F0E3E3FC +:1539030063C651F487FF17618E7ED64E877B5BCF813F7EC78161 +:15391800C6783EF0A8CB3A53398234F74FA31D4656B60FEDE209 +:15392D00BDAC49A71F5450AFB51AE737D2214D100FA83D40DB6E +:153942000532DF5B66EE21BB48B5C00B8326C61FDEC26D1FA1AC +:15395700FBE170AE7355A66BA9245A672FD0F6C97CCA736254CD +:15396C0080388215C75F9DE19772FB2E4DCB6265A4EFAA03DE24 +:153981002201EB4C23EAB7A0DD41DCCF37C18F49C9C2FE1A2F08 +:153996009F37EE02BAF1801711FA66BCCABEA3720E7D437141CA +:1539AB008B9B3F3CC83F3DA0BEE177F2AD2DE49BB2F38DDBB65E +:1539C000677700AF385A86B695E47E964B18B4FE2E4534AEAEF2 +:1539D500BD9F379B0CC1443FA095D94EE5579BD306CA4392991B +:1539EA00813CE3FDB82EB9A3668342BCAA6E637FAD8967CCCFD0 +:1539FF00F6F3F2678DA341AB7D34429A263337DA02E923905F61 +:153A1400D702E609417A0BB63F4B236C68A77415CAA076FB725B +:153A2900D545FBA3E6EF8C1D3531254A792AFD317043FC83ABCF +:153A3E00E11B87BC4B614E70A3B9D7889A0FA4BB4D7D34065FA4 +:153A5300DCD38BC17F16C215282BE7B36DF1B20CE1009015D890 +:153A6800519351FACD8C711BE41B07D8FCD85E01572DF015E0BB +:153A7D008B362E6508AF85FFD590871FBE8D3077DB00FFE716D1 +:153A920060DB065C815F37F8F1C06F9E02BF50D0A2477C8E4D94 +:153AA7005FF7D30915DA5D854FE6979714D18B4378E47103D74A +:153ABC00A042F2B826E0FFE5F4E5E83C48448BB958C5D5995BCC +:153AD10022D86F4A3B642D4B3A81CD7A359E6991068C52DA2366 +:153AE600E6869C3C3250667D7A8CCE0570350975C67E4B14E2A1 +:153AFB00453406F90D215EFC4D05DEA69CC231AD5945BBE28BDE +:153B1000E5DEA56CD32B8353CF32E6E4C3360D68999FD8FB05AF +:153B25009BC63413FE51074328C0D3A12FC47105C39EB5F48CEF +:153B3A005B1CFE047ED99FA0AEDEB2E502C00A3207C1EDD09B26 +:153B4F00492097DBE9826CF972B6A983F277F46D310DE45551D0 +:153B6400C9BA280CF32A0B5E8A2FECDF7E6E461F5EC2BB96FCCD +:153B7900FB0A75ECFA31D6F1807A030C0DD29726F4F88F11604E +:153B8E00B44D64ADF7EBE0CEC03B096F16DE1CBC26BCD3787B99 +:153BA300758E0CAD3119DE50CE8ACB360D5A75B574E6C9CD7E81 +:153BB80039DB2DCF7147E7B8E373DC8939EECC1C77768EDB9CD5 +:153BCD00E366BF9A53FEAF8A74FA013FDDDC6CFB0393483BFFD1 +:153BE20064C16E531CEA161838AC56D2D9503B1F9873E3DCFA61 +:153BF70086F8BA48E0D8849ECE219D66F03605EEB3F09E83F799 +:153C0C0002BC02D0A71ADE2678DBE1ED86578177C34FACB8ECF6 +:153C2100D004E12DE3D01FDC8837BDC88D784B14B9116F1B8B77 +:153C3600DC88B778911BF1162B7223DEA2456EC45BA8C88D78AC +:153C4B00938BCBFFD58C5D442A1FDC818E8C816D1BF54BF97BFD +:153C6000D65DEB9C6B279C5DCE3E03E0576445F89D1BE74F0C29 +:153C750047DE7314E417908DF427E6310FEA1AC29CBA33CD31E8 +:153C8A008F00FFC0673A451823CBE545D73C05E3622DFC231DFB +:153C9F0079699B7A971778D67C5671076BEC8CCEB778DA4DF0DC +:153CB4001F996FF1B23AD6B8DCD11B91D1CE2F8CF93AE48138E6 +:153CC9009BAE84F11BD29FAB44D9E1D1193B0A20EF9DA91F80D0 +:153CDE0071793FCA08FAF40AF7F227208EECBDFCF8E48C73B8E8 +:153CF3009789E311A0D1531C4F8472B7DA67BC41DE597E16F2D1 +:153D0800F290FC3E9B8FD502BC9B251C0F51BED8AEEF88E3B99A +:153D1D009E47F52DD1FD547FCF87DCBD92DCAC23CF6F03B4794F +:153D320057EEC6B5306DE33C5CCF1FD399FEA81E80B97B271B90 +:153D4700A4F8839E0985AB6987B175CCC07B8078905BC9B66F83 +:153D5C006C587B6A3E8E637ABFE44D511E47459021218D203F57 +:153D7100AAF330167B2A715D6ECC401B0688E746C9923F10D617 +:153D86009C385BBEDB378F553C01F965E6E138D3A827696C6ACA +:153D9B00A2B109CF137235213A9F7EF662DE539E18E874C79ABA +:153DB00054596ED05F5CC12DBF0BD24CCDB76422070F3E5B5772 +:153DC5006B66FD43D6A7A7914F6D25BB6B98BF74FA030A9ED3D9 +:153DDA0040987DD1B1A53CC82A3CE4390D79F6824C85E7407863 +:153DEF00D265A57138407607A62D9BA17C7CC21065EBFED03C4A +:153E0400E9413FAA0580E7F3F26306C6AF043E4AF7A59780FC2C +:153E19008C770C16DDDF721EF2F8511CDA5E1C6D16587691BFD7 +:153E2E00CBC63A4570E33883B88C9633CFEBD0665F65039D0EF2 +:153E4300EC164EF6116FC23CE8CC045BD2E9C07D1EE046FD401A +:153E5800A04305DAF9C0B6C1A3DED985BCC7B1FB5D5CA7605144 +:153E6D009D9CF106EB45FBBCC0EF102E777618E039AA511DA462 +:153E8200319C7340BDB7CFD89D8D0F68231EE6B9016075D27CEB +:153E9700383AD8897BD4FF7CE0E7FB45B9C50890AEA70A7D760A +:153EAC00B5E1C0CECBFB691E86FF38C64B368ED6D8703A7A6FBD +:153EC100362E03B8BFD60261BE38BFDC5F32D337244FA36ADD4C +:153ED600E39AA6F28CE3E3CB5924827BD6796BEF219FFFF2F1E0 +:153EEB0008F82575BC5BC09BBB57F59EBE56918EAF54EB645735 +:153F000017E9B4E6B6A30E89C7533C6EDA70B6B225342E4F0ACC +:153F1500CCF334D4F167D0F6D8A6AF525E185F405E1F19A77B66 +:153F2A000BE8FC47570B9D7B00395CFF6662AC13CF44207E1FE7 +:153F3F00887374AF9C8D779FCF747756A1BC6E1ED3CFDFFC9DFD +:153F5400E53F0337D69937272EDFDE0047567BB3DA8F681ED6B2 +:153F6900779BEEDE60D7049587FDCCA2A74C3875F835DFB5043E +:153F7E00F729315CAFCB8E459CFAC6B8D9ED12F5122EC6B94E46 +:153F930084DBC1DB4BD971E201621C78825DCECF208F775BA70C +:153FA8003AD3BD3C543EBB2D76BF9EF7AC063A8AF1A2BAC88FA0 +:153FBD00E9A87F56A80BCC61ACFA3715EA8270F05D1FA4BA1001 +:153FD2009EE2636F8927B7D4A8DAEB1E79ACAF707C17E9FAE127 +:153FE700DC688FCBE6138003E0E99E82CDF1DC8076F2BF1C7DE8 +:153FFC00CB16AA13EACF3A696F837448EF34A429E63377BF6960 +:15401100B55751DEAFCBF171ED73D18930968D6D51DA7CD43A54 +:1540260057969B80F9C2A041F6E1A72D5EEEF415DE3C60489E81 +:15403B0009D50B3CF77E985B8926F215CDAEFF9199FA43BBA8E9 +:15405000EA3A46F5AF02BAD9F42D8C21E5C8EFA83F68AA6507E9 +:15406500DCEA0F17D1164AE4D0ACFEF09BEC21B28F82386BBD10 +:15407A00C53AEF8DE53CCC863BA12D5BFDA46BD06AC700EB5097 +:15408F0002CF30EBFDBBC9B6F9B139F4D62D7AD71F5D6E805B09 +:1540A4008C8F17D1F5908E6966E83A6ED72B45F5429EE3ED1A8C +:1540B900A63A2DCCF0CBB1ED3BB42CB45FF0E333686B3FA90FC2 +:1540CE0041FFB3ECEC5BF5F802B44FA72DFAD8D1CE4A281F618E +:1540E300B900B02C84B677A86C76DB3BF99FD0EEE422F8E200AC +:1540F8005FBC083ED981CFE24B84CFAE4182AF982F4C4F5B7B51 +:15410D00C8F8E5E3D69DB37A34B9B1B268CC49FCDE694B85B9DC +:15412200AB8F454608B768CB223D9DAF28B43D906D7E81BADD7A +:154137005FE5AF95E2D6FCDB17DDAF3E0969020D7CAFF7745A0A +:15414C007171CCBB00C3728774E97446E1610E7E10609570CC13 +:1541610081F683EB92828072A7A6058347FA65909112F78EF437 +:154176006E41FFD4EF90876F114E1EA37DF073F5C3CB58EEA8CC +:15418B006E84B85ECCA72E398C36C1FC5578BF10F827613ECE96 +:1541A000A4618387FC708F93DC502E4F7B2AC306A5C3B2F461E7 +:1541B500D4175D5097E13B07AC345B1230A7C77511618DA6D2CC +:1541CA00FDBCA87364CFE91156CC7F6BB7A694F49C5713F9BC33 +:1541DF006FE4239A8275E6214D5DF2C03A841FC74E840561C3C2 +:1541F4003D8476802170FA88521587BA9EF88AEA631AF0F08C51 +:15420900F22D1C17EC3CD1FE3CC8C03E4CE7D47D08F24FED3C5F +:15421E004CF7FE627BA1B8B1435B84EDBF534D840DEA8475C1C0 +:154233007B41912E8807A61FD3109F6DA83600E10E2ECE16F0E9 +:15424800609555C003AEBFE62C3C04BFCF77A67A70AF79421B7B +:15425D0000FF11EC2F8013F4C3B50D1C832D788F010E0E289865 +:154272007F49CF6BEA66C2C301C50BF5431C48782E05F74EF013 +:15428700CE0D280B6DDA86A0FCBAE0B97EC75EAD65DF04E6FFDB +:15429C00AF30B6A326A5BCCACE698B42ECD38D32FF61C79E62DB +:1542B100EE9364AF96ECCE74D31AC19251EB6C608AD245CD6D7D +:1542C6001AB46D0F7C711FCDC8BD36D3CEF13C18AE55611B6D33 +:1542DB00C1B934EA1E86DA35F61AE9B58DC2989B4D34B97B3965 +:1542F00021A2F289B0BA0760AD5726F19E385D977777D1FC14F6 +:15430500E248C03B44F9639D82FCD94E49FEC4723E26E3789DC3 +:15431A007D0EE461FCF6E35C2AF628D9BC0D74C886953FCA8CB7 +:15432F0063D91084B540FA2648DF08E9D1AF56FE44A79307B46F +:15434400A74E11C205087F6EC567293F91E666AF6C71E26CC493 +:154359007200267FC7B495B76EC18D388A60DF00385BE467BB1B +:15436E00F88E901183705C2FE882F934970AAB5202F7D2ACF8F1 +:15438300981FB481000FF9603CD2E77E0DCF015AF769601F6EDA +:1543980067F6FC1ADBBC346E97B3AF1F6D3254D3D97DCB0FE76F +:1543AD004CE8876D2260E9B05F325FE2388B9E057FC8BFD6990B +:1543C200FF901E1F944F7704650CF3B54BE75CD6D9C17D3A8668 +:1543D70021FF015E6B95057102B9AFA9FED35F53505EF5771D0F +:1543EC00B2EEE580303FCEFDD9611CDFB58FBF50C26AB387DBB4 +:1544010036C2B827DAF30C4B67D09273D066BC9038B0B40A64E3 +:154416004F3FE61BDA67C151E0932982CF1F4D46C83E04B8311D +:15442B00CFEAE8785B6D519E85B90BF05C4A6FF3CFDFD8ED19DF +:15444000EB81733B80CDF71CADE934CEA4293E8F48F76DDFA789 +:15445500FDF632E9F6CF4907ED5DBFDC7A52D4DCABFDFB65D2F4 +:15446A00DFF52ED2BF7C997491778477AF76EE32E9DE60EF5C67 +:15447F00DEF49B73F6D3707DA7B8FD01ADA65F9BBDBE31373CC9 +:15449400F1FADB874FBF53F8FF76FE73C2C5E2F6FF76EB03FFC6 +:1544A9001FFE47854B45F8F7CDE54BFF67E0B7DB47ECBDA5C765 +:1544BE00FEB580974916FB24D9B869EA1F94E2B7AD82AE287AF2 +:1544D3006F573508C7BB56C5EBB6AB74D607656EEF0675DEEA92 +:1544E800EDAA2CDFA9CDBB6E40F5F7688AC835A8FECA063509AF +:1544FD00728BDDA7D75D80B159F236A998DF1F9BD7DEEB35652F +:154512001275FF7A70EE12D7502389974B7A3F073C392036A83C +:15452700E53D2DEAC3D7372BF53DCD4A50BC4D1D2CF98082F66E +:15453C002017F17167AEE2C7F83C77A54A6B0FAB078877200F1F +:15455100A9AF4C2AA8DFE584FB28BC59757B1324DFD5DF9450C1 +:15456600697FC9BE2F7C2E0CAB6C182A0086BD0043A0A87C2C1D +:15457B00B70E60C078942FE45F5CF6053BDFE9A27CF3F967F20B +:15459000229E150FB3DEB578473AE49D28896B888F3CB3F2BAA4 +:1545A5009AB10555801B11CAF4AC69061C35288BC416B5F6430B +:1545BA007CAF9B0DF4D57F9EEFDD3B3F4934C0759110C0817BDE +:1545CF00705791DD9019D81126929358E21EAA1BC074D286E933 +:1545E40028D65DBC51ADDFB956E52A1DD8F2171DD83A01B66A62 +:1545F900B181FC1320203AF4F254B6A822C1B45D595499547755 +:15460E006DDD51680B88E73FE4F3360C8CEA893695ACFDE3E983 +:154623007BB0DC9C0D075793C2BBA784F99A05837767A3EA852E +:15463800F2B06EBDB62E3F2ABD115ECA66F0520F6DA7624D974C +:15464D001AE889103CDB4AB62BE580970A31A996B264DF0EBB47 +:154662006D2EA6BACF947B0ECAD221CC0BF802BAFB1C1890F65F +:15467700F5DD372A280BD5F7DCA8CCA53F74226F39ED1BCCF4C2 +:15468C00A7FAA93D148F3BD5A2066E8AAB3CBB539D07711FE630 +:1546A10058D06DFF1BF05FD10370427BA9A88CA8DAE31DCADEFE +:1546B600131D4AC5A9356A4003BF9DAB55ED233740DBBF41C1A6 +:1546CB003610009CD6AFB170C1C7B95E996DA0B60D729ADFCD92 +:1546E000DDA28AF112BCF7C4EFC1BD9ABAEEFE79DCADAAC8AF72 +:1546F50052C59550DE7577A8E2EA1BD4E192554A04D70156CE75 +:15470A00C42F0B5AE766287E326CC57FF233AAF844873ABC35B0 +:15471F00ACB861DCF53E7E9B52FFA1925EB48D2C24C27D9E6CDC +:1547340047DFFD684F4A0BABF5A76E51B9931DAA067139618691 +:15474900169BB08F07E99CCD3AB4A5220C40BAE31D7D34D76B64 +:15475E0067BDA5DE505F99B7BDAF3EB556D906BC4106FF21F8F1 +:154773007E1A79CE4FD6ABE250878A72B52CDF8AB29D20263FAF +:15478800A3726BEE5429ECC90E080FABC38033A43FB6719C93FD +:15479D0094FF03D75B7F0A70A80DA881539F512B4E6EA736B0B1 +:1547B2000BDAC03CA07D7954EB2BE64B4877A41DE928DB34C57B +:1547C70036791DC0D28BF0039EF16EBF1EF84F96DCA5CC837208 +:1547DC0010FEC1ADD6FFAA8BF900F225C78D71616C58B7278FDB +:1547F1006B3856DB36606A85F843BE0773AE054EBBBA1BE290E4 +:154806003E39C070D71CFD4AEFE3B54AFDC96AC06DB57AB97630 +:15481B00F4129B6947BF64563B421A94433B0A8A77115E1EB6C7 +:15483000DB12B6A380067E73DAD2F6C49FAF2F0F6E00FAC4FB9D +:15484500B7B35BD7CF0BC6FA39F10ED57157446F5D8F749A376F +:15485A00B0B68F9DE8ED73BEF52FBBE87E9DF2C4DABE8A6C6F1C +:15486F001FE7019A5FD9A0B9810E1781F688BFAB8916AEDE0ABE +:154884006D0BD0E10EA0C30EE2E9C5B428B16991B4EEF5F17365 +:15489900C29550766CDD14D105DB4D6CDDD13974019AF86EB218 +:1548AE00E9027CD7B7B6882EEF2BA2CBABA43339D3B7B742BF10 +:1548C3001E29A213D987863680FE9B6D5A9D063A39B4D9F01E37 +:1548D800E971A6881E3FB2E9817D3A60D3E2123A006D8A695101 +:1548ED0016FDD4FAD2E8DAF5EC6ED62B663FD5374FDAD057C62A +:15490200FE7A7D79E26FFAC4ECADE4AEFF3CF5579FC8C01DBD70 +:1549170093F0CE6F6ED05CC07B2F96C5B47207EFD04F2BC4AD95 +:15492C00C0FFFE42AD5873EF2CBC975F0EEFA9C548F322BCC7E7 +:1549410009EF4E7D8BF10F3CDF779D8D7F5C13C17EE2E0DF5732 +:15495600847F17AD6D58F81DB1F15B897C0AC2F0DEF0E23EE01F +:15496B00A47F89C6058B66988EECD3DB74B0701E9905CB97015C +:15498000CF6286EB7D12BE49E03DA59007DE9FBCF763B7A9F5A9 +:154995003D5D8A54B254292BB956C1362C02EF61273AFAF6FE68 +:1549AA000B849D5AA3F84A3EA2784A3E6A8571ABFAD8F537F4B0 +:1549BF006D8BBB7A11AEC5F69DF2D046BCA5B28BC648F4477B35 +:1549D40018CE1C05CB47BB9125CED86D8F1F180F75A511AEE79C +:1549E900F3793FC429F4FD27A1EFE3D87506A693B85E82F2017F +:1549FE008C75FE27ECF8DF82FFFA9779FCFA8E505E2975976B5E +:154A1300FC36D4D3629C7597298C2C795F74FC768369A4F38504 +:104A2800FEFE99F5D6F2FF06E2E5D1A4A89C0000A7 +:00000001FF diff -u --recursive --new-file v2.3.47/linux/drivers/atm/sba200e_ecd.data linux/drivers/atm/sba200e_ecd.data --- v2.3.47/linux/drivers/atm/sba200e_ecd.data Wed Dec 31 16:00:00 1969 +++ linux/drivers/atm/sba200e_ecd.data Mon Feb 21 16:32:27 2000 @@ -0,0 +1,928 @@ +:150000001F8B0808AC5A10380203736261323030655F65636426 +:150015002E62696E327D00DC3A0D6C14D7996FD7B3F5AE71CCD4 +:15002A0078592F3F8DD70F0AA949E8DD022E07F61A1644AA40C3 +:15003F00012D88A433EE52268844E8924B571792229D1B0F8EB1 +:15005400013B7DD0C7608813E1640D5E58529C6C909D101DE4AC +:1500690016357749A4E4BA8A7227541DC9AA17295C4A2F76455E +:15007E00259438EC7DDF9B19EF7831C4A1524F772B8DDF9BF742 +:15009300BEF7FDBFEFFBDE1B3FFCD3BF7F88B808896E2484FED3 +:1500A8008890844A880EFD1CB4BBA00DB710128396439B8076CC +:1500BD0018DA4E68B51FC3036D16DA1DB8364E88026DE92FBA6D +:1500D2001EFE486452BF7C63D90D63AE825E0863FB54E1A984C2 +:1500E700782F999F6AB59F9E3C49B19D522690D8ED9FFB737D9F +:1500FC00FCD38F45DB66F353D2B6AD1433AEF2F2F209D77F491D +:15011100BE34E18787275C3FF52678EDF13693B20B7EE47FE17D +:15012600E71A20BB45FB4AA95D5E29DC72DD983C8589E52B4C68 +:15013B00927E7959B9A987A7DA6E4DCF24842D778E97CC7F63BA +:15015000F90B6D6DE8BEAEEBF97C299D49C95956A43F7A5BF4D5 +:150165005F7C512AA1FBB7D87EF4AFBF99905E79919E97FCDF83 +:15017A00FFB93C759E5BCDF3F48DEFDA29E89C2A8EA109DC0E0B +:15018F005FF8FFFE2B387E24ACB3FC6765A432BB6F911CF4C674 +:1501A400C1977CFA72F2308031121A8EE3BC3E026FE14E96FF67 +:1501B900025AF9AA21793BD46B5B3B1A708EC8A429FF1CF1557A +:1501CE003E4F7C81FDC4977802FA5DC447C2618EEBEA932EC057 +:1501E3004BB79000C012130F873C52EDEA50657DA14AB86BAFA6 +:1501F80014D4B75C5C467C1D4F126F20B8231E269759EF9EFE32 +:15020D009D846F61249CE1FA03844C0B6A716FD52F20EB9C6518 +:1502220035C1447C7AEB6916F59268404FA9249C341086C4F6C2 +:15023700182477ACC79FE300570FFC87E3FBC3A4657AEB6A1692 +:15024C0085F4D4BE7FB34AE4F5AC7D7DB3FA3C213546D2DD045F +:150261007C32C81F7230EF6A9E22B7A8B81EE7116EDFCCCB8A9D +:1502760067E549751FF5B490DC6C5641483010844C26EF66BEA1 +:15028B006067FCC3B9C4E721F3D53DC3EE1669F72655BAB04CF6 +:1502A00095B6AC654B008EF03EFD6EBA6531EA08F113F958A63E +:1502B500F8F4EB015853B966BE7AB950A8FEB04D8DB4FF933BA0 +:1502CA00021254BC2478DA75DB3C456FC2D306E429775C5F2546 +:1502DF0078A202FFB7626115F9D9AB95B5608BFC601B04DD5402 +:1502F4000575C0F90BA1C39DD5640A91FBF4DC8A2D0DE780D715 +:150309001DC0AB3D1FAB26E3C3487898BD07DA0F053964FC6180 +:15031E00B09F6E2C85F4EFDDC054B2B33F93978886ED30B49447 +:15033300768879E085CA723BCEF75CC37918AB1763BB718C8F81 +:15034800E218973A503F887F41CB78FCF545FC0256ACB3E8DA10 +:15035D0034052D8BEE84341DF8D924F1874DFC62BDC065D1B458 +:1503720069396575E2BF52823F5CC47F03AE9BF17F2BFD283F5C +:15038700BE7DFE1BC41863C362AC4325B1FE8C3D3EF66ED31296 +:15039C00F6BE39FF0257281DAF69ED17F8883C2F83386A5A1923 +:1503B1001BB5E418C30B73E3E48AF573539E9BF37F2BFCD76E07 +:1503C600827FCCEEB1FE1E1B7F838D9FA45929AE521C387FCD8B +:1503DB00E143B62C02A73CD433A10CE3F647A7B91FAAFA55D204 +:1503F00030CFB4AD06B685FE0DBED990327DD38903EC5BB9A572 +:15040500685F6F5587E09B3474B0AC44A2105B784D2CAD1ECE76 +:15041A00B85B80BE512D77A9570A85A0D33FD6FD99EB3BC4FAF6 +:15042F00CE09D78FAD053C57715DCCE12B18A2352F4BE4DF3E26 +:15044400A3E73F3562F9670D7FEEAC3AFD034D21B14BAC4EB966 +:15045900475D4C7FC5F6DC3B9020F2BF81EF26793FC4F5605035 +:15046E0089631EE0D00FC49222DEE3788D3E00FDB481E324B744 +:15048300A8470EEE8A93DC7B10B366C4F7CDDCA178E9E3ACFDEA +:15049800FD956A27C4B7F6F7D7837DE688787987152FBF0532CD +:1504AD00C87598AB92BC1BCF26E134E7D056692EE07F3ED0CF67 +:1504C20033CC96D2CAB56AA12CCB24D72A55EADDC8BAC949C5A3 +:1504D700A50DB0EEB2E30AC28C421A3D4C5E56C05E0CAB886E6F +:1504EC00F23A8C67712DF4FF45113C02DE68FE6D03E4309096C9 +:15050100DB45AABB203749D1BBD5BB80A7629CBF17F86C6701DD +:15051600E06D6788F8BC40FB933677C4BBE135950CFEDCC09CF9 +:15052B0087FC728B5FC455F5515EED2E3BA9A05ED65592181934 +:150540001C30B244C0E918E7BB519E705AC4FC2A42FC2496D294 +:1505550047B7F635873457A377C309F0B30106F089DD3F9C0F86 +:15056A00364FF16B85424D9DF26B359AFF9457B94EA8B1FCDB9D +:15057F009C84327177E57915E18379C83D202BD2385A0672CBE6 +:1505940003461053742C63CEC97F32C0F601EF8697D559078ED5 +:1505A900C3BE4D097EC0EE19B0BBD8136BE99A8829F3A21ECFAA +:1505BE00CAE3AAB013E634CB4601878D1EADB5725A02721ADA1A +:1505D30000748276C8A27FA15F800E9016D959D40FEAE5975DB2 +:1505E800DF079D844D9D583CD83A09002E874EAA854E56AC5F7D +:1505FD002CF0900C0BB60AF9C00FF764AC07F676126B984CB013 +:1506120055E82BFA3CD80FD619159837071F671F423DF547CC48 +:150627009D9ABBB94EF94FD5EDFED9920D9ABB2948DDCDE3ED05 +:15063C007B3FE4F1ACE201DD96CA8CF2A1DC1EB2006AA3679877 +:150651000CB2CABD9BD88E3B896FAFB6B1C9BBE105F0796ED6EE +:1506660014E1A5ACB002FD803221E3D52B26CFBC5F7F80DEBF28 +:15067B00988492F15AB2470D8C32C12FE9EF63DDD98560AF85B3 +:1506900006ECCF8CF5F4E05E053D0AD9486CD0C0F501D8C35394 +:1506A5001C72BD05754ABA6D6364519B29DBDD753F5B485DC4FE +:1506BA006BCAFA6BF53A79F216B2E641D6939396B5F5DBC477B6 +:1506CF004CC8FA30C8BAC39435047BBBE1F7A67CB1E3FA532095 +:1506E4005F6DF63BEAD4489390AD2C36430DE9A1E66F635D12CB +:1506F9003B20628096FFDC38EB2553A0E5B81F85AE5007644910 +:15070E00D12FE4BE8CF5801EFA8A7AC8BD6A209D523DF4801E4A +:1507230074D043D0D24325E80169074B68831F4E194FF38472E3 +:15073800C0972AEED189F7E6346B6F46C6E6D1C78027EC8760F4 +:15074D00EF3AF72BEE55C253FAB5151EC10BC417D8AF2761BF9D +:150762007ECADD9543AA6BE659D5D53524F6EC11C79EED297B45 +:15077700C5DEB37E9C3F52DCB335E8FFE8D7CE7D3B0BE05046FB +:15078C00BF4346AD9C4C71EEE7B1FC943BCDFDC1CBF1EA46B191 +:1507A1005788F48AD452BDAC53F4AB5DEB45BC8E06486C8EF056 +:1507B6005F6EE65EC88572F20A93D6ACC59C974940CE2B4C4D3A +:1507CB00B05EFDB8C2662694C06E880F77A4541FFA4FCCB0FC60 +:1507E00087C7671D931ABD55AB61BFC6581BD118FA4ADA05352E +:1507F50041586188A322F20CD3A03568598B1F7CEB04ACF36627 +:15080A008FA9011DF3FFEF0D51CBE01EF84BB6DB3E6764B09B53 +:15081F00E9E04BC89773FE51F0AD1524C1B6E9879693F065A3B1 +:150834001E6581396FB61DCE4A585F7C435A0F9AB4B278CE7380 +:15084900CCAD4A8E3621FE34B9357E5D33D7E74BD637265BC568 +:15085E00FAA513ACA7DA492677758B1C6DCF47110FCCDD958C37 +:1508730034A1FEEDB501FD984A61CE8BF0B1B9803B950925C1C8 +:15088800A6164C8305238BF5A9CC647C22F0A6D48CF11F7DAC82 +:15089D00167D35D76F94D64FEB1E76D43FA2AE642C8AB58F2916 +:1508B200DF196CCD7ACFEA53689DF58F63FD1C0D7D1060A1FEDC +:1508C700411CD21AA61EC43D0BF2E27E1A572BE3F1F93E2FEEED +:1508DC0053C31FCCC6F17C5BA75C51FF86BE06E7DDA19D24F6BF +:1508F10004C39C9E7B40D4893C8BF50E9C875D33CD9A270A7153 +:1509060003EB2B92DB8E7006C2C9C119702E7E5A9C8BA747FA68 +:15091B00C59938181D54B1CEC0F544AE15676212AA8F4F8F3447 +:150930008873309E89CB8066FBFEFBADF3F0BDEAF32EFB3CBC70 +:15094500D43C7BDE10C78B67CF89F2349E3DDFAA29397B62AE9C +:15095A00B6CFC3B992F33087986B3F373B0F7F4D8C7C4CDB1875 +:15096F00F11C3CA3BA601DC6BA3D10C776BF9B56BC55C7314647 +:150984008A5A40C43898C739A0853569CD9CA4A7C98449A13EBA +:15099900A222060A9B891858EDADFA15F8C48098DB4EACF36D2F +:1509AE0091DF1EC423D60B9D9B7024F62763F7BB19657A24259F +:1509C3006C00670103C726F7FCB3217C16EC1BA8492A585360D5 +:1509D8002C47BF7906F9224BD94BA843FB5EE0366C531F98D827 +:1509ED003613DD0B94C796AA28EB3EBC178056DC0B403BFE5E71 +:150A020060693CEEBAF15EE0EB6CD6FE17B0D944FAE413D8D15A +:150A17005B750FD830CA2C7939CAEB6D9D6DE290470CBF43DE6A +:150A2C00042153049FAD7D967D070C8499DC73613C3F729F6190 +:150A4100E39D01786D5BDBF1E9CE478AF1C5E5EB107ADA94DD30 +:150A5600D3689F51E58D49A5A67590C5800FAC0FF04CAA79CD1A +:150A6B003C8DF05CE80DFC0A748363EE92B161475C9A41E7F61F +:150A800060CCB93802B97A659F1AD0D07F1A18C81E708580C77E +:150A950031BED23C564648A3E66944597640DFB5C63C7FE1F838 +:150AAA00E1DA2106B508F7C82F412CEF33EEA4A70D29B9C7210B +:150ABF0097CE104EFF119EB74C5C4B268B2B79AA880BE087AD61 +:150AD40073A08BE8784634F0DDA6F34DE4D11DF2F43878D02783 +:150AE900290FC2651E30E5D11DF27C2DAE1279AE96C873F536FA +:150AFE00E5C938E479C7C1436692F2205CFE7E539E8C439EAFE6 +:150B1300C55522CFB51279AEDDA63CC991A23C67478A3CE0F891 +:150B280064E44138D99207FB4B268BAB449ED11279461DF2440C +:150B3D00ADFB0C19F3B9E5E3750A53EFFB09D2357D04DF975A45 +:150B5200EF19EBBDDE7A47FAF83E43BC2799F065A0B1AB4CB4FF +:150B6700ECAAF59EB6DEAF59EF17ADF751EBFD1DC0B38B9EE038 +:150B7C00D8D760AE93BECCC5BD03F47BE86B5CD403D04FD337E7 +:150B91007994DEC5CC73C5592303EBE05C51334BF33407939EC7 +:150BA600667FDED3EC053B606D8F3236D05302CF7658BB9ABEDF +:150BBB002AF074437F337D83E3FAB74C3E38D2DC4E777313AFA4 +:150BD0006E0C025EBC6B5841DE6167B6BEBC5CDC59004C15F5B9 +:150BE50034E2D80B5B5F136359C7D8335BDF1463C8933DF6E484 +:150BFA00D6BDCB6DFC7751D37E886796E8A7F9768B3EF2B4B65E +:150C0F006E60998DD386455C36ACCD2BF216B26011EF5F514FEF +:150C2400B3B84BB1743AFC88A9D39CF8EE61CA3EC3CE1F304F8C +:150C3900C7CD9BF4EEB6700C9A638CFF9D09F3A1850369071099 +:150C4E0007CC651F2DCE452C3DC6617E1DE80F75C7A01FA7072F +:150C6300399E8FCE099E2E0B3E1FA5CFF15EA1DF1EE3F48870DB +:150C780040FF03D73D4D7B67526543E88D85CFE692CA0F962315 +:150C8D001F9D424715509B2E592E352D0AED5EC861EE6E319754 +:150CA20011FC56243D8DB3DE949A82A1830B0D98AB5A6EF28FE3 +:150CB700FAAA807D72FD2BA9E98BDAE7161E82B93F367B9A2BEB +:150CCC00B4F2C6CF2EFD2182387F57CB22B8FEB7BD831184FDD0 +:150CE100E0D269C8FB3B044DE03FA38B7686E019E4CCC444BBDF +:150CF6004BE026E1682629DA84E0036A8E0CEE89E9172EABAEBD +:150D0B00F735D87FAFB0CA60268EFA31D75D36368BD6D41109F9 +:150D20006B8602EDB495C755D7FA47A0F6D9CFEEC05C097A3363 +:150D3500E9268D0ED1EE303A45DB23F4590EE705D7FEC701FEB1 +:150D4A007BAC2A1806782A6219C20F8A36619C15ED52A1F32969 +:150D5F001700FEFD7F10B5D5D4600CE0A386C977D2E887F6692B +:150D740061875D467AA498DB4808EAADB0226CB30D6C93A007C3 +:150D8900B81CCCC1D845B6B4CCBA2B17ED45A301DA9DDF273E14 +:150D9E001E76B7C0318F1D182DF8D1971E85F14A7A02EA055D0D +:150DB300E8AF0CCE160BBE8370E6BEC25CB9CD82457D5BFB8D79 +:150DC80061FF29A029FBDE533B9625AD6F6D507FC1B896FF8DAF +:150DDD0011681D62E8C0DBF3AF1BF0CE75E02D104DA9B20FCFF3 +:150DF20039EF1B121D323E69B0F8A1B3D9F52F4D1A4761BD6C70 +:150E0700F1C32D7E8ECE29F283B9EE030B36EBE0277B0B7E623A +:150E1C000E7E36033FF0CEF904FC6C76F0F39845E33DDC47160B +:150E31003F598B9F4A073F98AB5659B0E86F363FD8BF193F51AC +:150E4600073FAB811F78E7C909F8796B71919F8FBE30699C1BBB +:150E5B00C19C66F28334909FD6D9457E30D79C3161052D37C413 +:150E7000D68EE694310A676A3BC63A3F0F6874906BF434C4E84F +:150E8500CD4C0EDE173FBC2CCDF0FF560EE74E2AD65D9091B78B +:150E9A0062CA7F8CE0652EF17B1D79334EFB7959D57995E60779 +:150EAF0058714DDAB868C5631B5601B86ED8DB7E888DCEF53124 +:150EC400DACD37037D05F850E85178AEF0049DCB77D105E03353 +:150ED9000DBC9346C056AB799DB24D35C8A1447D3EC5BAF55427 +:150EEE00A207E093F41C4F53C60FF79E663564409DB6A597D514 +:150F03005EBAC23AB67C97EDA99DCFF66E59C8F6F52E639D97C5 +:150F180056B223B56718DED37CFCDB32DCD30CFFB7E7D9DEF32D +:150F2D00ACF2C231F5E0A5FD500FEC5FE2E4EB9D30F155D1D593 +:150F4200CD6363B176D6B090F8FCCE3121403B3B7A93F1CDD75E +:150F57000A378C2B5A3BC77889FA09D44FB08EB7B33B9B26184E +:150F6C00875AE06A1DF179434911ABC046F2DCE4318EF6C5F74D +:150F81004F46AC1A413EC789CCB844C51D2BBF8AFF6810E6FCBA +:150F96009A687BF8A8DBAC7586451B66A4007551554AEDD6878E +:150FAB00946EBD5F9926A5D4236543CA91E88072186CF9ACFEB4 +:150FC00086E27DEF0FAA8005E0837A9722AF632AFA4185833FB6 +:150FD500BC8390D890187F52AB6CFCC4FE770F2B6EFCFB0A33BF +:150FEA003F6A63B934C991E73990C72A925F35CC4A3E8179C4C6 +:150FFF00CA8567451D63E6AFB366AC039D99F98F5B303D026617 +:1510140047314F8AFDF09845277B039D3BC6D131F3E559510FD6 +:15102900D97432169D0F2D3A264C0F33E3709A87AF12D21B76BE +:15103E00B5941F48A981E83CBCDFF3FBB5EF468290ABAE5E372C +:15105300E5FD40FBEBC6CBD0F782FEEB14380779061290B39AFC +:151068005DA1745CA678DF1B66C92CC489A4AB65333D652C022E +:15107D001C92FC3DC8435D3C14DD1F3948BA13788676877AE21E +:15109200D23D50A3C5468CB974C4705BBA8ED02E234A0F1A8197 +:1510A7007C8A734F6AE702DA67605C895D0039F2FD5C069C38D8 +:1510BC000E276206072EAF93E6A617FA9A9DEBEB9443AA61E19E +:1510D100C0B5D8475C147049A1FA78B464BD1FD647E97306D4F3 +:1510E60010D6FAEE09D7E7FE1173537D1C7909C3DC02A833C232 +:1510FB00B48BE1DD96413A120AFD2FC3E3C238779A19E470422A +:15111000D23A0C3FE46037D6BBB17EC3AB751B95DA39718F365C +:15112500DE8FCF5A7EAC8FF3E331FFCDA614D9E1BF55502B8C04 +:15113A00F928F801DA0F7DB4FCC0805A43E6A9A66CF5A66CD11A +:15114F00BE66A73F0768170F6A529384E766C29917ECB1733E0C +:15116400F1E1FBBE999DCAC54DC4F7E2CCA422D3F9C236ABD16A +:151179000EB096AFEE7E085BCF52F13F2D15B383264E79893719 +:15118E002E43FF568F0947444B8336DF14F65D1D91AB16A81DE5 +:1511A300EEF90F79AC71EED71FB2E7F1FF6AE4E8DC07251B479E +:1511B800B4FB41BFDD5F591C17FB04E498438E36617E801A931D +:1511CD004E8BF5604D631CA2520BD51883B37A0061360998CB74 +:1511E200D6779F4EBCA3A0247692076973837DCF82DF034657E0 +:1511F700342F36BFD19B7797884F4E7633C487637EB95B7D077F +:15120C00713AE82F17B829C33B5949FE0CE87719B80EE95BEBFC +:1512210032B80EE89D71F62F3AF158BF83B9E39073F0FBEF1552 +:15123600568DF74FFC285B8BFB92DE1B09D2798DCC8A0F3FA1C4 +:15124B000F35EA629F778AEFE5BBA75C413ADC2F3F67DE75C28B +:1512600018E4AB1A1BBFA4CD6558B309D81F7EDE4272FD7C9ADA +:1512750003B6C2829520374F16EE10F0BA0AE2DD0B5A5D13D6FA +:15128A0008E677FE432A9C9E184473435AF339F8E46CD63B4C08 +:15129F00104FA67AF42893454EE83FF3BB42A11AEF06B789B5BD +:1512B40069B17681B69FD5C84FAB776AE759448333656C9E811D +:1512C900F489DC6F081EB09F4B19923C5745DC52FEA88DDBE4E5 +:1512DE0011F6DA589FA78C2CD058A44D6FACD2A6477EA04D6DF9 +:1512F30044BE376975CDB67C923C5B2D956F3273820F7BACC455 +:151308007E7C18BF7D9F03DB65E24B08A9C63AC6E53BA7BEE98E +:15131D00C2FBC734D64D747A10725E6CC8C0DA424A0E31D7BBE7 +:15133200E7D5FF065E7B5CC48BF6C77BF9465AD358456B227E15 +:151347007A47E366D0D32A5ADBB8CEB237E2A8965F1577D4E057 +:15135C000C34289F51CB80C60298AF86BE1BFA088773F6B90BB5 +:15137100E15DD638AE0F26E78571BD8CB2027D19F8284CA5ECCB +:1513860008E953189C8702AE3EF17DE059F17F5203D67D685A64 +:15139B009CD1719F797D57D4368823337C4755D7CC4EF57052CB +:1513B0006AA9B9705E9D23EE5933868EDF5E760E88EF34384755 +:1513C5008E0DB1CBE2FB0C65B3C8A9E508432C18F17DA56F880C +:1513DA00CDD2BE6A126B89398EDF4DF4248EFFBC89C883064DB6 +:1513EF00A6F03B8821AF1950A330EED79AC5B817DEA980AB6D72 +:1514040092F05E22F6BA7118FC026582FD5F8D7715B3A2A71B27 +:15141900C59D456ED038AC4942EF788FF70CC43C5BC6A0252368 +:15142E00CA11B1F27D7D01CF75FF43CC13064755A4D993BC91CC +:151443001988C3038611280C0F1CD6E045326894648038C168C9 +:151458002556E40688EE7B5CD089266EB450729055768B5B5FCA +:15146D003081041F5CF34C206BE1DE84CD94932B2203071A3D8B +:15148200ACCBDE79BB68A5AE721677C7D5B9DEECD69E4779615E +:151497008D6CDC65AB38E7BEAFBBDFCC9BC9A0E0DED5FD987AC3 +:1514AC006FBEEEF77D5F7FFDF5F77DDDFD7547F5F31B315A88AC +:1514C1001BB88ED10BB618607BCEF31C0253B2E941318E59B05A +:1514D600E751CCF18671A03F4CDCB28FC53814642D3F01387A39 +:1514EB00433155770FB3BC0699D9A328ABEF954FB03595493179 +:151500002F4698A20CB3BD8A291B2C2060E47206562A6057702E +:151515006D46C454576DDF30DD1B292025CAB0698761DCE8CF5F +:15152A00819102899467C3E8203CE5C8192A83AFA9C032D15E21 +:15153F00DC8F21F4769E6B22BEBFF4E59C7F70B1EFE3D4E291CB +:151554003FC5FFF019EAE881BE606BC0316AD10929C3F44592AE +:1515690030FAF4188BBB3F01BB07D1C3168CBB93E9B888CB7601 +:15157E00C1548AC935947C3DCD6728F916EDE819566B6CBC2309 +:151593004EF46F7DA14186B319437E5C0345D9C8C3B42F1C65B4 +:1515A800F07A019F12B1117B029F3EDC2F92193EA6035EFC1FE0 +:1515BD008E1956FFA7447F768BFE64BA60C90D6224A00FF3A197 +:1515D200D7696F826C29B2D96359B4C7259E72CEF3BD2FD3E9DE +:1515E700C559F685CBFB75B6CF555344C27ADD1915C74C0DDB68 +:1515FC0013E730B2613AACC00E2BC6711C376BC1E339C47B8D20 +:15161100CCE1A1E409E0F7049D3FC9E4EED3053F0C0636CD57B4 +:15162600191773BF8421C3372C8708FA8C3DC3678CD9888F0E7C +:15163B009BF9EA933CF549BAFE5B5CD600837773773ADE8E53ED +:151650006931CC3E443BF19DB5C90BBC5B6D82F729479CE97FDA +:15166500C09B29DF579729B7607BF3C0A40DD3614E3B2C67FFB1 +:15167A0091E9BB1863D6F8B58FED8E9CB18D4FE7C7710DCBAE50 +:15168F00F58D9EE71BABEC255B19C674ED8BC82CCBA6A03CAC55 +:1516A400727C5F72A1536BC8299F85B4EF47DA71A3028C776FB2 +:1516B900C4B945C6BD0EC0157E28639F5037702C5865E5F6325F +:1516CE0090834BE0614F1B8EA21C1C56FBB9FE71989E0B037C5D +:1516E3007B2C983703D3F3C0667AB261D8A62E5B9B2D58671E54 +:1516F80058A1C70ED38D4431D8B685423E246AA0FDC0F1E915CD +:15170D00FA1E4FEB3BC0D017D8D63A4811616B1AA8BF5EA6BF42 +:1517220031C3D2F39907713D3C418FC2B8F785B86DCB8743BE31 +:15173700611C5086397BF230D6331B6CF350B4EF681FB7A15DC2 +:15174C00C1B526F8EEC0C2B8CAF0839EC14490E683CB36B861D9 +:15176100AFBF203F5C0678AB43D8DF626E732D99615C500F659D +:1517760079E5E5CDDFD6591F27B43E7DB8EDC0C284CA7310AFE4 +:15178B00436EFF8BB8B09D5FD507C68DF0F58D7165F76B42D8B7 +:1517A0007BCB77737B9C2DEB6C7B9C8717F886F302710A3E0187 +:1517B500F76CC4C7F6C3F3C8214F7D92AE9FCDDF6E9BDEE11865 +:1517CA007678A68F71E2993EC60B3CD3C733C903DBEF9E3EC6AB +:1517DF009D9EE9E359CA8161FD57ECDF66E6BC221EC371CE7D03 +:1517F40003CA7489CDF7C15397785C62129B2F9473CA245B99AC +:1518090037A7CC652B5B905356642B5B2C0B3F129834E23DC8D7 +:15181E00972EF2CBAD582446838A3390893D6294E5EA425F6464 +:15183300628FA8C6E38C9CD853CEE4C8C8BE924647DD2AE853AA +:1518480098670742867C3B2105072B357D32E5763A3AD5367878 +:15185D004A20935E85AFC3FE0874EA70F4F7E5646A805EE941AA +:15187200044EC44576EDFFFFFDD5D610F7D86729370D75A835F8 +:15188700F749EBACBD4DDC2F24EDFA293667688F9E1A67CFD1D9 +:15189C00532CC7AA3D796A929DC989D2C446BE16678B410D07AF +:1518B10019FE18E539713F71ABF7F3BC65EE67BBC1CF0E829F2F +:1518C600051FC9E456C2E466F9EA1AE083783AD5F2CF84EC22A0 +:1518DB000E263BB47D51C0E307F847F749AB91D6D98D7C8C8CD2 +:1518F000C013D71B1D0A8B154DFCBF212BF68CD107BF617F17F3 +:15190500B179E0A4896D045924842C12421609218B04CAA2F079 +:15191A005E57A33D7EB95EF9E158F228CB033395AEC0D1422EFD +:15192F002B0EBB13600702F12CD83D00EB0B9CB66045089B0F62 +:15194400B05B03A30863FB3A5CA6572E810C4196172F4D9765C3 +:15195900C37AE2BE700965E95F7DBDEDBADEF69CCBA30F054261 +:15196E001F3EAA26EEDAEA6C3E2B24E2AE075E9CC0EBDA3CBC7E +:15198300C6A17E29E3B574F58DF4C1F5F27B3C0FBF8582DF525A +:15199800A0DD1F9AAEBFFA35F4B77322E52E8076B44F4C6F471A +:1519AD0012F0344F603BBCAB6F54976EA43DF13CED91447B1A71 +:1519C200818773F7417BBE01FDD6FF8236297E2A2BA594D97E0D +:1519D700B0798EBB0889001CFF4BA4D6D88DEF01D550403A8B99 +:1519EC0015CD9495EA57D91E33D899FA08AE37478DF001EE1352 +:151A010095837CAE32FE32F86249077FD8CDD64B0DA837161922 +:151A1600328B9A4E9A139F72DC7EC09B9AAD1B53F0DFC1FFBBA4 +:151A2B002E7C9ACDCF0551F70A3C1B20DEF42A9C1E51393DA4D7 +:151A400083F4D02BDBE92D867A454D43663DD0DB2D709CFE9440 +:151A5500D3EB14F4E0BFCB2E4F59C8B3086489E5ED5524AB7C94 +:151A6A008E65FFAA7879434EF95C513E26CACB73CAE789F2E328 +:151A7F00A2DCCBCA278D1A9A39CF92823652D2A5E2DE9D0B7DD7 +:151A940074CEF9956E888768D4B905E28CAD55B8AEA977AD2A29 +:151AA90056A4A02AE29A9E8517D5AAD0BE60AD2D5F60CF48D3BE +:151ABE000728ABE7DB3FAC0AD8E01FFFF0E5AB085FB3F5832A70 +:151AD3007B7EC18537BFFF1AC29FF8DB9F559162DCDBEE373A7F +:151AE800FFE5856AAF4FDF4A1E236E974ADCD3F8B4E58F2987E0 +:151AFD00B2FD338F35264DB4210E0F9FC331989CDD362B3EC2C4 +:151B12007A3341D7A7D6F2DC19ACDB5337ACCE8C3C12D85FC732 +:151B2700EC391DB5EC39945967724637E69FEF1B9FA7DCF14B5D +:151B3C002977661E46B55EDDAFE2BE0AC48DEEEE8551753D59D3 +:151B51001EF490E5AB16298EE0799045CF42AA6ED0FDC17369BF +:151B6600B9C4D99AC4CD4C1E740FC6284E88F50673CADDB672FB +:151B7B0009CA3B3372ED2E9048B70BCA1D65D07FA2CE22E6D307 +:151B9000F8B73741FD0651FF0EB0FF3EE1DFB0CC07651584EB9F +:151BA50013FE5F7261402B81FF8B6C75965C8869DE1C7E1E8494 +:151BBA007E4A4462A60B7C6CF96F53EEE8D594BBF9CBD42CD1C5 +:151BCF00BE7511B0D3A03F5976C52BF45442F9839E86927F6EF3 +:151BE400E84E320BF50CE3600B37AE5FE21EA16CE30B73854FA4 +:151BF90047980F360222BFA108F02E00F97B9712B7EEE7BABFE7 +:151C0E00600DE016FB3054F8F31749BFD13B3AA8BEB90CF7E984 +:151C230002068F654B0C561EA830D07717B863DA0F963E5CEE8D +:151C3800AD8CD2D65732F1168577A90F2255788EC2EF1CFC9498 +:151C4D005EB0AFF01B17BFD65EBEFE85F82EFE12D7BF94C6F455 +:151C6200BC4CC0A3FFC1E161012F009F5683EF7480CE837E2B7B +:151C770000FF50CCD618264DE9DB84BC823E830E9896DCADF9D7 +:151C8C000796596D9394037406B3ADD4083C4A48D17FA6DC93CD +:151CA100249BAEEE22B370AD1BF1FF33CC476702DD31A81376E8 +:151CB600733F65E191051EF932E76DF493947B90E7F5883A101A +:151CCB0007D1210DC7EC646A361B23B837D6F7F7C7198C4CCED0 +:151CE00026DE9F0EF277F883F2CED48D9AB89FD6377A5C9D2F99 +:151CF500B1F50E93EFB3454DDC575B6BA3C3D71DFB8DC7C61FD8 +:151D0A001B5F363A98A53F37A3FE209FA043814ADCA386B8203C +:151D1F003C443146DBAFAC0BB01C45CC8D8BBC4B95C819C3C77B +:151D340072E8BF303D7CED9BF68A7557BE8E3BC2F70C020ADF8D +:151D49002F40BA387EC227CDE7593FDC40FC373E8438D2F3B0B3 +:151D5E00AFE741D0065A69FA79F475DB3AF0CB69FB17A5E3B899 +:151D7300D62B1BEC9C14192D20E037D8FA3EE0A0631B591E841D +:151D8800CF9A67CD2103EC0C12CA784CD834FCBEFB5EE296C690 +:151D9D005FD2E40F5F52ED362D6D77D99C6CC448FDD57B923824 +:151DB2003324A32D66F3191AA37790C120E6EA4FFDFB7095BD05 +:151DC7006F6E1263BBA482E45D1FE56B9BBAC03B22F026742EFA +:151DDC003FC0ABC738DE25C7B3F0CE1078C757E7E0457B08F1E8 +:151DF100D5BE85FD2A3BAF0F3610F126393E7D19EEC9CB83B482 +:151E06003039AC4BC933BAAB28C6D6F966029DB961AA3922869F +:151E1B007128296D91944EE316F91D6D2C95F279A25230334FC2 +:151E30000D1B1877EE72A0ADAA6DB4CEDD635E358B4B587EE23F +:151E4500A4A9E2B3B8A291C80FBCCAE64201E554E8D13CED0713 +:151E5A00FF15E847FFD5CFFCD7BE8523AA67B4EB5E466F5CEA4B +:151E6F00A49571CE7B38A67B301E13F082484C972B13AC7D8726 +:151E8400C801D584B1ECDA30C8F6D1BE85361EFAC411194EB76D +:151E99006F6E6830687DCBED46FA7D1A3FFDFD997CEC7DE0FFB5 +:151EAE003DBAE0875E831F80CB601F91173B4D07DF4FDF9375AB +:151EC3002604ED1501BE8B47F83C5FC44F203B2E1F9E4F922D53 +:151ED80047B9EBD5ACFD0B186FC88303FA1AD73F43C9237B8A4E +:151EED00F95C4DFF25C07BC351D5E5116B64C0D3C5421DCF3873 +:151F0200CFC2F2B64D3C470A7DCC3231BFAB653A12D7FF14CA3C +:151F17002CDE19DF507FD7261607B33C8E7A51EF7BB67AD5C94A +:151F2C00D7F7C04F47786213DBD3D0314F00DB82F349E4A3F77A +:151F4100A598EA1DE5FC20DCA2DB2AF09DCC4377C446779BA8EC +:151F5600F7B6ADDE7AA08BF5466DF5DA44BD9FE4E16F7DF2845B +:151F6B008EE3EA1CE3F16F74F403B5789E06F83BCC746798AD4C +:151F800015F7FE1DF04A0619AFB5365EDB05EEF7F3F03A6EE3A1 +:151F95006197A8F78F7978BD60ABB75BD4FBD7AFE035BA39C326 +:151FAA006BFDD7F05A6FE33529700F6C9ECE6B7C7386875F8943 +:151FBF007A439BAFD19F9B33FD59738DFEACB1D1BD68F5671EA7 +:151FD400BA2336BA13567F5E836E77038EAFB328031AB6D3C5F7 +:151FE900F68AFB3F106EE9FC7EA87F84C4D23ADFE0E43A7FD59C +:151FFE00C1755E6FC8D00E3B39ED8E86AFA00D741B045D8B5E7B +:1520130083AD9D0D02474F7E1C14C7ACB516ADE6DA3C3C4FF630 +:152028005AC6DEB1F18CE771E5E394F92FBCB7473E4D31CE73E4 +:15203D00157569FB206E94C197C9F5EF6A0B8C33DA41DCA3B7F4 +:15205200D9A01F40BBF2D91EEB3B9F23A61ED18755D417BEF704 +:15206700774085F9EA1E9C9FAE67B832BEE12EC055007E216DFF +:15207C005743C3AA6B438CD954664F2D7FA1A33D8D317B2AD7C5 +:1520910001FF60471DB6F7ACF61663BE4EBFEA5848B514E65951 +:1520A600E0BAEF659EFBC57D5382D3A7C29E86FB786C07BE8FF4 +:1520BB00B765909DE791C3BA46D12F4586C12FBDADB9A2670C99 +:1520D000F44D79FDC98F32F33B9ECFD0A9F970BB1AD712C4FFBC +:1520E500A9546A5EEE5C8FAF47B2FD70B3640AECAB1BC656B88C +:1520FA00D4A0A18E36B4C5AE426E93252BCEC6F32DBF4BA57368 +:15210F003F9529969F39DF9E372855F27B70545B3DBC8028B73B +:152124001EFA84C30A9EA11AA188E7093C4355E6C0DBD558FC4D +:15213900EB284E3462F92DA141ED96D0DBA8336615D6C19800DF +:15214E00F3A901EEDB1A3333FFDFD618ECCF6218A3101F4D680E +:15216300FCFBB7D1A77B0B3C1DDA7BBFCDF0E49F6271928DA775 +:152178008451454EAEF1298E80451BEF02BA83D18C52ACEFBB81 +:15218D00F50B33FDBEEE8B349DE492936B0BD2795F309F147980 +:1521A200F8C8D7FC5B3127A28F9AEC2C5729CB19BA17C5217371 +:1521B7005CBC6E9CA2FCC12D9AB2BC17FAFA347CD36B4ACA69E7 +:1521CC00B3D1164F5E7C84906714E79AB30E316FCD43E7218C26 +:1521E1005DF2E2F69B4EF94DC07DD620B4CF94A2EF9A986F8196 +:1521F600EB9F69DF8DF38A42317E11EFB7C57D14A20CFFE7B9AD +:15220B00EF83E596A21E4DCC40BE127482E78C5397E0CF65E79A +:1522200003FA1BF945BCBE6082E51BB1BC0FF9A4897CC83F5F73 +:152235008EBC73DD13EBF1150319FD463C138F703CFE298E9FB9 +:15224A00E34D30F9CCFF791775C01C0EEFAFE823C32A9EA3C3D2 +:15225F0098977F9330B14ED63800FCC707ECF7C9F07623FEC926 +:152274004778FB389D78161D6B4D00EB323926B91C6FD9DA6987 +:15228900E23D116C4E63A7993E5F1B32382F1586CCE4526BF06A +:15229E009C8480E112F9A00C1E1EA44F2DC5D8F518CB47B4F334 +:1522B300E07D6D39B5F71DD431257908F7E6A9A5272CC606DB7A +:1522C8007A9874AAECDEA8B0C1E4827C61B904EDA515BA819379 +:1522DD00E4C2A24E8D1EB8533B7F21E526E3036CFEEDC53E92E8 +:1522F2004F6992F22EF545F8F9796BEEB2A070FAFCA9A36E8876 +:15230700CDE7B2E650E327CD7B6F740E15FE4BD3D229CC23ECDB +:15231C0077F2F969B64E711D425E4A845C589F04A33C7F4D1EC1 +:1523310030713E8DFE0CF5097580C94AE773E9A35FA6E6D8F47E +:15234600384B9F59DE7800C63E9D30E6F9028DB87EE2519697DC +:15235B007F88FE14E6E9CF287706AFC098BC2BE965E7B07B1FA4 +:15237000E5F4E38FE2251B0798DE610E97809B083F27E6B551F3 +:152385005137915357C04D841F15E3DDC2FF9EF8E67CCE37023B +:15239A006E22BC55E03F27EA2673EA0AB889F0B502FF3281BF77 +:1523AF0053D4C57AF8BED8666FBA6D65F88E67DBF04C9B0BF426 +:1523C400A8107C95A40C98282F49DEAFA19F092883788676EE70 +:1523D900DC505F9504F3D3F91D135A9132642ED22FADF5557FB6 +:1523EE00A64991D3E66B51E71617CFFB9C373332638D14993002 +:152403002D9D9D09B62D7915D7D13263E0FBE02325766E884EE9 +:152418001B8F627CA5ED0AE2900F0E68BD85832AF23677ABDF7C +:15242D00B4C633D301B409101B3892EFB2FD46FEFD88993B9E8E +:1524420079FE24D08431631F272FDDDCA925FE89AFF3C9C2A6AC +:152457007DDD38D98BB9A2D618E91960392BB2F0A7385696619D +:15246C006E00C41A8FB1B5F7CCDED306C51910E7A9FEF0FD47F0 +:15248100DB78AA2DF83FB0D139F1445819A04E4F17936729E02E +:15249600ABFF2CE377E9E7397E1778C13A44EEC03326265B170D +:1524AB00298E373A0FC6B43ED015796D8CDFCF00B8703D05C6F8 +:1524C000E33C764700F8662CC77BC33087D8F2BFB8BFAA46965F +:1524D500D2420FDEBDD7618CFF3A435BCE1387B8224097AF4988 +:1524EA0098D85F7DE0F7E5B303C6154113FB378B2694BB7268E4 +:1524FF0066B7BFA4B1C1463F6CA3AFE4A12FD9E82FCE43DF7F80 +:1525140083F431BEE8AC0C18162FC8C3D825CEC362A0954B5FF5 +:152529003E3BC46829910103EF4082B9B789B18FA4F03B8F16DC +:15253E004706E861887BD0A74DD9E31C5C7393FD66679DA1E108 +:152553005D60532FFAABD87E5FC96D2BFC75CD41E54F2A2AB7BB +:152568002A0FFEF1A60794CDDFDBD9DEF2EC4E6553CBB696A616 +:15257D009D2D41A5FAF107B7EF686968DDFEDDEFB4B63F5EBE5C +:15259200F2EE9501A5E4999DAD4FEFD8B1FDB9C79B9E6F0AADAF +:1525A7005A55B9EAEE157F7497F2D4D3DB5A762A81CAB255156B +:1525BC006595ABE125581E0896DFADF8D3FB5B16BDB2B2E696EB +:1525D100B6EDED654F6E7FB6ADACA9B9A96DE70B65CF363DFDA7 +:1525E6005CD9CE1D4F96B5EC6C2B7BEA85B2A6A66D0CB66DFB24 +:1525FB00F6B6953B6F5B758F72A7D2D2FC74BBD2DCF254D3775B +:15261000B7B52B4FB6363DF79D16A564577BCBAEF61548E5FA76 +:15262500F037EF78FAF9961D654F41B31E6F6A7FF6F1E61DCF95 +:15263A00AF7CF2B67B2AAE853F8D9E9D679AE30B37EE67F71A4D +:15264F00F88DB9BE8AC612A59CAEC4B35CD6398D88B406EFD1B8 +:1526640038143AD25640FA8DC6DFA7D2E7341A958DE627BF703B +:15267900AC91E48735BF526DF861EC7D0CB6C40BCF37D176E26F +:15268E003E09DD6FB47E9172FF74A9146C50866829942D22C3C6 +:1526A3005521A587B2F2B0B4370030B4376B6D30AC27830F04B5 +:1526B8009C66B752B4CEF2090BC036CE203C96C0FF5701F73E78 +:1526CD00F9E5368C13CFFD756A16F2653FD7603FD310BDC2F71F +:1526E200CABA58FD12A31FEA13F9B2E9856FCE027D3B4FB48D99 +:1526F700B0B3D32B1D642EF2877C78959314DB3003E6A998E3FD +:15270C0046C657E03EA9D7577DA7866DEF02393A7F52A9E1B5D5 +:152721006A7EC0C5D7AB0E1961E58746CD08D08678CA0BDF5BC8 +:1527360074F01C97B77A850630D34EF3A1548AD1EC62FD72CC9E +:15274B003C9D4ACDC1FBC4F8BA738F7113F805C439F916AEE733 +:152760000700768CF1E5047F7908F90AEFC775B9F956BF5967CC +:152775006CA2BFC3BEBBCCFA0EF7571405C69DDC957029F7980F +:15278A00CEEAE3D0DF07186E1C8738068B94D7CCD22F1D6BED4A +:15279F00EBBF28734BDEF67EA87927E5FAAAF2D27752B3ECFD49 +:1527B40081FCC8C08FD7D65F6D1197114DFEEC556C93121D4848 +:1527C900CCC13BE7E8622314ED4890E2B6464F926CF14697828B +:1527DE003F3EC7EEC3F3F96AA1ED0F18787F29CE1DDF9470BE3A +:1527F300A41A18D348EF3FA3E11D51F5B8CF12C6B3DB611693D4 +:15280800F6EA41D50C55AEDBA414ACFBD079D1F0856E67EB8DA0 +:15281D00462235EB23B12F128AF6D09BB2F4A01EF3BFE763BD01 +:1528320066A8773ABDAF1231F07EEE40B49A12F915EA666D83D9 +:15284700793795F63ADCEB35DC4767F617BEDFE3C0F58C8BFC2C +:15285C00CEAAE601889DCB204E78925E29242ECFD880F69872A0 +:152871007370AE72F3AA3796CE0FBEBAECD6E018C091DED4894A +:15288600D4AC658A23C8F8917B0C5C7376C1383C0F7A9FDE0F44 +:15289B001B3FC6FDF1F831F32F1696A86C7D186CE4D142116F97 +:1528B000290EB6761A075C565DAB5E3BD4395837A0E29DA7C812 +:1528C5002FAEE7E6D2C2F18BDFB7C2F7EF39385FB8A679E10D71 +:1528DA001C3F7BE9E2A241CDFBDF47282A4A6D14CFB45F64E72D +:1528EF00E7CCD0EB6A1FE05D5454AADD8577C28E47D55272D174 +:15290400E80C9D68C33D2E05FBA96E8566429FA0AE38770F1B8D +:15291900B8B71FC4F58EF08F791F88B18B31B4C4E6610AF015FA +:15292E006A64FC877F6C8E4DA5DCA70B783BD7439FAECDD37719 +:15294300308F9E9FDBA6DEA914CBE9403CEDE2FB4530C69CE3B3 +:152958003A8C83FD4601CC4B42C923863196725BDFCE80B1811F +:15296D0036F0AC903BEEA7A22CC22007AB4E3F94B1F7F1970D63 +:15298200CCA762FB8F50A7F48D6CD95F0539E6E315C7ED82680B +:1529970007F57FCE653E359CFD1D933FEA33B305FB0D4BD6BDC7 +:1529AC0020EBDAE88079F5B8F0F9F676A34E8A761FFD0D6F378E +:1529C100F63DE2DB05F84A599F458C5D2C6E133AFA2BAEA378CF +:1529D6007EDA51F780867B86DFB2F450F40997670657E8379C5D +:1529EB00E736D00DE083E9C6A2A2B59AEF178EA0A523783CBFC9 +:152A00008DEFB30A1D39A3625CB78C9C5987FAE1AD4C30BD3021 +:152A1500F565AAEBFD214D025BBB4CE8035F0FC8EEFF1190B788 +:152A2A004F3EC6E29DD9A01F5EB0BF577E2DE46E8D0BDB37B8AA +:152A3F00679D4FEE2B717C437D94FD343A30AE7A218EAC17FDA3 +:152A54003EC3A623EDA023AD1F701D71809C25A123E597B99C53 +:152A690059EE01F6FFF14C3F223E4FB84D6BFDB7B672B0676627 +:152A7E0049B4CEF447FFA7BDEF8F8EE2B8F3AC1EF54833D22015 +:152A93005AC3CC20B0905A443892A33833625024598481B05E2D +:152AA8009910769673B2DD92B0C7B1BD109B64B93B6E1FEF85E7 +:152ABD00C42318890137B8E913589615337224AF7C0B398507C9 +:152AD200397C4F24E2C239B021DC2C211C9764F1388FD8BAACE3 +:152AE700CF283E62E3C466EEFBA9EE1E8D846CECDDBDF7EE8F21 +:152AFC009B7EF3BAEBF7B7BEDF6F557DABEA5BDF5A69AC4D3DC0 +:152B110064AC4ED519D4075AF65353DC2E34E6371EB9869F2B10 +:152B26000ACEB2EE45FDB55654BA5B0DDE817DA2914EC869824F +:152B3B007B50C5FAD98475AE1E32F7037C3D69949F0DE4EB5DA3 +:152B5000B09131CED8A10527686E3ACCD7BEA454B701BDC4D514 +:152B6500A9935CDE8BA786C193F324B9DB582D9F34747AFBF5F8 +:152B7A0011F5B46C86B3EA61EDEA07C8832E36E6FE07F17305BB +:152B8F005F77BC253C273C2C7C56F00937D8AFD97F633F64DFE9 +:152BA40063C3EC5966B0DD6C07DBCEFE9A6D618FB38DEC61F62A +:152BB90020EB600AFB125BCFFE8C7D917D81B5B17BD96AB68A61 +:152BCE00AD642BD8729A41B6B066D6C41AD93216664B59030BD8 +:152BE300B120FB0CBB9B7D9AD5D3F3297617ABA3A7967D929E0F +:152BF8003BD9127A6AE8F9043D8BE9A9A647A6A78A3F95F42CC7 +:152C0D00E24F057FEEE0CF42EB59C09F72EB999F7B02D6E3CFE1 +:152C22003DBEBC675EDEE39DF694CD78A45B9EB9B73CA5B33E15 +:152C3700733EF0F17CE85372DBA7F8233FEEDB3E2E6E3B338E52 +:152C4C00F3B1C15A4DE6674B4856A96CEA8C32F928FC6AC84FD6 +:152C6100B7BE6BE93B6D7DD7D3B724D037FA96CA5A8A1FD17442 +:152C7600D6A6A569522C098A26C98B8F4A31FAA7E89F597C1419 +:152C8B00E598B6496BB90D3659B6FCDC969F407E31CBAFD8F202 +:152CA00073905FCAF22BB1FC0AC80FF95199FC2CAAC4A2412BC1 +:152CB5002FE8F906AD3CA0D71BB4D2428F374869A202F66465D7 +:152CCA002D880E49BE4BA3D975BF93E469F845B99D8790EE4D6B +:152CDF00090DAE3375D4FEABFB5D679A558E9F0F091BFD90302C +:152CF4006E7F87C24A298CFC0DF88B679B555E76BACEB07167CF +:152D0900E31CF5485B30EA2F719AE8329F770775CCF318EAC994 +:152D1E00D3043B815FE0507298F1E3A7AC70EA135BE5C5866EE7 +:152D3300E593FA2FA67F94E245D15F4A8B0DD105BBA3B3BFA3AF +:152D4800C2549C74DEB7E498FAD62D7F8EFFF1EC5CE82698E770 +:152D5D00F7656DD2B4C76AEA6D705D4699EB74145ADFFC9CB4E6 +:152D720083788DD11C34D8447DA783251C4D4611ECA1469AD5B9 +:152D8700C9EA66BE1E37F943E732E0046EAC898E533A0F6B8218 +:152D9C004EB4514FB8A08E5673C90D4611BB8B60BFCB700622DC +:152DB1009DE959FC24C1F463F25B06FADADA996B124159E77EE0 +:152DC600E0EF029CCB151A44A29914EF6A10313F96AAF537A019 +:152DDB003B2F85A8C826BD9EAF3BC17E6C33D7C9803BEA28A727 +:152DF00032EA74942F9E2957A5785D186F57BCAE01EF28EA9AFF +:152E05000E72191A71391FC3DE6230A8C5799B68D2225CD728D1 +:152E1A0002FF58766E1BC58972FB879095CD33CF312DC2F5F20E +:152E2F0037F133A82CB8C53C03CDB659F714242D5D08ACEBCEA1 +:152E440025A012345F49E83A4B28D8DF81FBAD15E23296DEA113 +:152E59007B64B1814577C2AE9C8BA565DDB4FF6AEA31D5670A9B +:152E6E001A789E941F5F47C277B4574F2E882B42AA17DF464EDC +:152E8300CF23FA5FFB50BF0AF9A02ECA670DA62768DE242EFB76 +:152E9800EE83DFA5FC5FEE833FFCEAC9AF7F865F39F9F5CCF080 +:152EAD00DBBA82E0925EEBFBFA83AF874860D63CF2157D1B3BFC +:152EC200A355AC7C5D6DAF7A25F46CD3045FB75814BF44F57999 +:152ED7004A5BB4F2BCEABA4FE336CACB2DBBF3934F88CBC4D496 +:152EEC0090EEA0F15196BFDFC7F4EB862B69DAE3E476D4C70FBC +:152F01003406307FA2F298FEB7C61DC2EB2AF051CC5E098D3CFA +:152F1600F86623C142B4BD42F09DD7056D9FFAEC86D7B43B22A6 +:152F2B005486B4CF20DCC56FAE581D72ED46F93B47D94821CDB2 +:152F4000E3BE33EA725DA3F05DFDAEB6D7C9FFE97ED3FD3796FB +:152F5500FB3FF59FC966FD7DF679C0E8CFFB128E333AF0B68DCF +:152F6A008D6BF11F14367CEB5B850DD07FE84F3FAB2CBCF0B4B0 +:152F7F005270FEA2BA865D0A2D1C3FA9422748F8C900F4F5CCDC +:152F94003A120D70EED52FFD07F5FA43578C85C2CB14E792E1D4 +:152FA9008A1F69C4BC15F94F3E745E77A50A1B469F285CC6F5AF +:152FBE00645FE26BDE47138E14D1FAB88E7AFCE1507738708AB3 +:152FD300F2977EA3A12E12608EFE68D485FD1069D75189C3FEC9 +:152FE800E3A3AF513B2C96F726B3244F16C9DDF1FD714D11D6BF +:152FFD0069D44E7FAEC36E288D00EC2917F610B4E464F5EF0D02 +:153012008ABBE74DB97E5994E26F8FAD6EE0EBAF05E6594D31D5 +:15302700F56DEA279D0DB1F1C30D4C3FAE4F82FFB0BE47E1EB7B +:15303C00C95F4C1D211EEAE6F6486A2D7B41BCBDE97BB9DDF0EB +:153051005ADED648AE4DEDA5B616D744A2ABC4B430DE2EA635C4 +:15306600E08D3D3257EA00EC1D733BA2E5A9842EB85EC63C93F4 +:15307B00DB0B052FA28DB8CE216CC88842EE4E258CBBE21AF7B7 +:153090007FEF27541EB921134ED2D4D013131BCA486E445B997A +:1530A500AC1E321606529D63379DCB0897C6E9F7B22E89E06916 +:1530BA00A5322EA16D05FB349DFAE156CA97A5068C8BBC7E4946 +:1530CF009DDAA91424C0DEEED6C24C3F053BDAA3E82F7747CE85 +:1530E4002BBF7EB4B0A18F752B7DF1034AE91271595F64AF3217 +:1530F9003FD1ABEEDFA929FB9B2F73D952CA1CEC5BB3A4F2B3DC +:15310E007C8F28181FC5DA6BD9A204F600F58A14AF8FB986EDC6 +:1531230032EDF5E3BB4D24193AF39A2EB411EFEAA78DFDE39A1A +:1531380082F541576A80D2ED028EF95E5E79E6A0519179CEA8B5 +:15314D0025BC54503D338524165038DA67ADBC8BDB6EE1794811 +:153162009A7191E6A1E5F2533AB7B1B841D3289D8EBE418C1DA2 +:15317700D3C3991F50DC5DD4467A699C1B509167762EF4786000 +:15318C004B80BAFC7327D583F15EC5BBB257756843AA6B7CB87A +:1531A10011E7E87DA78E98F6BC4F33B6003A00D029A39FB8AE2A +:1531B60047A57AF73BD6ED53134579776CA4B1D69FD4BEF10F46 +:1531CB00E28F0F0A9C667C0FC4977981EB03F25B806033057EB2 +:1531E0002CC1F5B78013733F24C9F7438CF15EA53CD3D317CC90 +:1531F500BC9092566ABC0F2958ABA9A2AC191E17F6B807B4DAA8 +:15320A00C881469CF3F277116FD1BCB63C0EF7712360B985B33F +:15321F0003AA392E1C307C194F03FCB0B6EFCAED8FF4F13D009A +:15323400077097EED56B389DCCF3C9021BD1A0476D9E4B1EE5BE +:153249007DE9AF282F612DFAB214A7AF903CA20616751B4F47B0 +:15325E00CC73AC584B17BEA071BBBA12A7B3693B5AE23CFF9D4E +:15327300A35761D392EA8DF56831437D5BFA3AA7435946C4B92C +:15328800E57980A79CDB5F4A76DA773430FD4903F6C100A7902A +:15329D00F986569B9917CAEFFBD1E783BEBCDFCFF5F9D4FF6FB5 +:1532B2002A6CF765DEC638C06DAB48991EE3B1F7B37EDFFBE0EC +:1532C700779306C0B12FB34F7768BD6A598BB9E7EFA07E03F7AF +:1532DC00DE7858EF520FF1D042D61B02FDCE7D798A77CF59B649 +:1532F1007F2F73DDAF894ECE7B4437B845BEDF11E7FB58A037C4 +:15330600E8CB6D5EA19D133D67D292E3DEA2C3ED70FB9169045F +:15331B001AE4E3DEA6C7C7A04131A7419FB5CF33458BDBD220BD +:153330006FECB5F11F1B87BDB4D2603E2DBCB14F86605F8345EF +:15334500BB466F3CF1C946295644E36C972E901FFAB1CDDF28C2 +:15335A006C38F147FB3CA0D99F9413ADBC8B3443A03A8176A8A8 +:15336F00A3B9E7639681F290B77DBE7D4A7E32E9B1208F16DB67 +:15338400393C49D3EE0E85635F51CAEC3304EBBE1BB8953CFDD8 +:15339900E3AD79E9B77E39A7E7CBF583FBD830D7DBDC049A7748 +:1533AE000D2B1ED9C9FBE92D5C0F50D31744CCBE29D7EEA8CE2A +:1533C300C2268CCBF4BEEF3CC701B553DFB63F98F5CDCCB8F661 +:1533D8000BF6DCCB03C9CE052413C82C7534C8C68F4658E668BC +:1533ED00F93F66DDF41E25F728F98F3659E93F28BE32313DBE77 +:15340200CB8A8F717EE0EDBC32B1DF48F391FCB4A80F9F7B51F9 +:153417007D6E92FCD28AF573792CFED499934A2189F6A2DC9BBD +:15342C00849D9A62F97412679ECDFDA0717EE651928FD13C2606 +:15344100A17B324B1A4E1FC8BA81878167B3EE9979E6C3C6F7CB +:1534560031296DABFC8C7EFD558D64259C19485A7CF8EF0DCEEC +:15346B00BB416EB37E723FC98F0D241F7D1CDE9C7CB5574F3836 +:15348000481E1D11DB275FD58C84A3CF6895F71B6FDF44FB88C7 +:153495005B73952EE32A6422A23FF657652A231F2737AE4CC7E0 +:1534AA0027F6772DF9D6D47FD60774C8D202B52FD491DC46F8DA +:1534BF00DF91FC188C72BBDF763E727A2A1FDFEFB3AE0A9CED31 +:1534D4000994C32EB47E91CADC06BBF91968DC46344FA6562FE1 +:1534E9003C15527F10AF0B753735F13EAB88D1DC287D9F562434 +:1534FE003C4C7DCB9A19B2A6639928DFA7CB99681FEC1CBB5C2A +:15351300D514DE66C9998B1B8B694EE3A8547859B08B0879DDE3 +:15352800D915524B23A17031953D54754F634546A631B3562FB7 +:15353D00CF0475C1D3A2767F3BA439C769FE986E326C7BD4D0FD +:1535520001E132BFD445F2674D4874134CD1AF8C32FDA17E5706 +:1535670012FB88FF9ABF332B1CCB6ED5BF29B7F4306AAD7E2D55 +:15357C0048FD5A9302B9DF2B0B413E9709364DD94049BF30BA8B +:15359100607C405D60DD59E0A3711C63314BBF64940957D55FDC +:1535A60057977E96914CCED88426B1DF34FA846B6A69B5B301F8 +:1535BB0072648464F60A6158D593DD4A39E618D46FA29F14DD49 +:1535D000AF73FB344CDA31FA00FBEF212ECBC1760CB91792FC9F +:1535E5008DB7FD5F2817B5E7DC83669A8FF23F9CCD06642ABF7B +:1535FA00D1CA9FDBF69F257FFB1F4F4DE57DA7FCA73C0DEC3F98 +:15360F0049B566F92E8259B6E250BF1E58287F32945F1FF84BF5 +:15362400DC864D11CDA95ED259E685A33E6AE7C998735945E6DD +:15363900A08EFE14BC8A7DF5329219DA16F42E8D903C8631F194 +:15364E004B4E9DCB608DCF68215BEEDAF47EF603E52ECFBBD91D +:153663000F94BB9A6691BB1CE78EA890BD206FD9F2574EEE8AAB +:153678000C37E28CBB6F25CEBABFAE35DD9CDE1FF23E9368DB97 +:15368D0056FD686331D7C99ED03CEC64A3EFD4FF22584E6A8B1D +:1536A200334B7278704D38DB6D3CC006D104E1E9DECC1C93BEB6 +:1536B700382B6386EB62F2B87A37A1A1006E2B0C7E080B4085CD +:1536CC006486DF091AAF3E088F243B841D6DD7D41BEF645DC0D6 +:1536E1002770566FE1B0E63D138715B3E010694EBFF32F8B4708 +:1536F6003FE457C2E3A2C089CECBC063747F5FECF733AE95B49A +:15370B007065F3FFEDDCF2CCF4D103FA1AD6A7DD4FF39DEFFF58 +:15372000AC77A92C9F1AA5514CF30A24A74A970C9FD54E45E8FD +:153735005348BF34B6B1CB5A99F0867AC7CA6BEA216A87341F91 +:15374A006FC01AB85466A898FBB2F401CD357E90DE07B53B5395 +:15375F00628397E6805EF6BAEA3D754515F8BD15A3DCBE14B79D +:15377400AFF4438C1B716D60FC07E13B28DE1D142F30DE13B21D +:153789006D3F4994066D54A638B63F6C3FC11FEDAB32736F4889 +:15379E009A28E434E736A7CE5EE16D0AF76905327786A6EC5777 +:1537B3005DE1FD43F0D5D2507EF9F2AB81696EE9D5CA696EE8E9 +:1537C8005BCDA7B2E673B8BAF3E03A990757771E5C272DB8FEA1 +:1537DD0084E072E6C175320FAE25A19976B582164FE7E0CAF8FC +:1537F200A7C3955934CD0D9EA9A0B1B531833E90DF11C9F8DC00 +:153807004700EF8C111DC61AE711CFCC3F457C263F63283769B9 +:15381C009E9E7E5E0F73FB865D7DF192443BDCDBF85D55C7FA7E +:15383100A00F5570866091BBFA1DE7BECD797284AFDD3CAF0766 +:15384600E5471BCDB897B5EB2B8A96791E7885E629BFD45DF29A +:15385B00F7FAEBE5FF61C47F37939F7A463DD07F4CADD7CC6F34 +:15387000CCF37B46275698F98C52BE3E2BCF1B2B3636DECDFE86 +:15388500A681CFD3F3E2222DF2C84F778EE2EC78F2921294FFC4 +:15389A006229FC21BFD134EECFF0FD0C64B8684F0AF323A42D33 +:1538AF00C6990FE25D9C27ACD8FF3CE763F4AFA2957FE9B4EFA6 +:1538C400F92187F9DD572CCF0DD15B7770BD769DE7EF786E8FEB +:1538D900CA714CF3761FC9FF46E405458A24D472C23F3FDF2953 +:1538EE009936FF6FF72799272924D7ABD85767D24E2E1749FE99 +:15390300B862CB455C4642D8C7908F6CD9C8929366958F201BEC +:1539180041460A731B30391947D3CF99328E598ECCCAE5DF195D +:15392D00F320EB92DCE492771B23D7B2AEE294962C26B8C3914D +:153942004483BD76514E7216E224AF8166DD3AAB15DBB75F33B8 +:15395700E5AEF11FF3701DE141C20FD2B3D4555D583041E3BBD3 +:15396C00466D21A915A612712F9523A58EF5A19F04DF214FCC1D +:15398100DFC17FB5F2ABFDE6BC7E265FF7F2FE653EC9C5DE53D5 +:153996007B492619D3C08315046BEB1FF3E55FAB8E54B7792958 +:1539AB00677BE6CDACBF96E4DD6DBF356556BE1741F09D79D3A5 +:1539C0004C531630CF6FB9ACFDDFD1F9CC4D7329F7C83CD38DB4 +:1539D500F3A3DB1DCC7D86FEE6FCB0D6B28F62EA383953423B4C +:1539EA00F33569F6D962CF4F894F4E35ABAB683EE6EC1A547BD6 +:1539FF00D3834AA5EC6C59287FFA73580BE669A43A35771E3916 +:153A14005A4D7C24F488B16ADD29615D59E879E3505D985DEFCD +:153A2900D2B6FC149750CD9C0F4D2F7F55BC6EE93FAB9C5BF459 +:153A3E00C7829D35F35989242D56A12F0E5D0DD843724A7FCB73 +:153A5300F57BEF4ABDDF0ADDBFC03743E8C3B84E1FB761111D23 +:153A680036D6523CBB3CF8B7927BEACE013E472F96024D9DA766 +:153A7D0003B0AF54DBF95E00F936987A72E5ACC4131BA4B1734E +:153A9200897AA72C34632FD513AB366E90BFF8CD2EDDD4AB1599 +:153AA7007B2E5AF32BA7B443FD1585C13E682FE250BDB0372D1B +:153ABC0043F78FFCC4D8A031067FFA7EA390B92F5BE98AC87D98 +:153AD10095FCF11E221AC35ED698C33CB3DB0B9AFB26614796E4 +:153AE600158DC02EE7354DBAF08C02BDEC729C75938E692ECFE7 +:153AFB0011751DD1769E2CB6176506349CF3A8A07E349041FC40 +:153B1000BD3B30C60996EDC0BB52AD4B258F797608B675E6F2B3 +:153B25003C87FB711F93CB8CE32B4F894B85915BD3B26811D7DC +:153B3A00D7D6096F61BF797616FA59B09B0A3D948C1F77C324AA +:153B4F0072F73188F2756333D14D24BC78A82DC7E89BCDB21F0F +:153B64001B8CB9B458E6C747C52B5DEA7B3E3BDF8A5CBE492BCA +:153B7900DF98653B7B0FF52D63458C9F1966E9B8C1F793A4B0E2 +:153B8E00265436758A995AC395811FD12AD3C4CB2FCF4C92FB54 +:153BA3004CA79449519EB14EACB3EF59B049E17D5BE596CE8A23 +:153BB8000C6C185CEE14E5AF196301933F6A284D6D26DD5F4F2A +:153BCD00E9C3945FEB3CE60E527A13B63FE9036CB0B3BC0A7361 +:153BE20028669F5B8E744632EF187B16449508CF53E98C929B8F +:153BF700E21F5D4DEF18E55D4873DAFB33878C48E6E9BEB68CD8 +:153C0C00DE1FA537F6A8A3F43D4EE10A9595F65AB6C4598AE365 +:153C210000F64B61F3B13393321EA17C63049B0FFC4AB8AAA7B5 +:153C3600B78BDEB0D12B5378057DAFA63C7CF4AEA1F9DA26FA1D +:153C4B009E9807DE265C915F1BF989D4D75C24BF60C0A4476CD9 +:153C6000864D72E795B84A7C57E295C5E50579F412008F3C64E5 +:153C7500604D35280F515F3764CC464FF33C53588B3A58C9DDD8 +:153C8A00A987C2683785CDB216E53AAD757A39BF43A8CB30756C +:153C9F001D841E3B8F149559D537C8CFB5080BE2EA947DA00895 +:153CB400C50B6B8CF2EB015E7CB5B9BE6DE2EF3106D6A9B8178D +:153CC90061B1DCBE946DFD5DB7F21BC6EC7CD8D62E2DF8736B0E +:153CDE00FF6BEBA0B685BE7B6467BB2B074FB3BE10E310C27EAD +:153CF30063EAC9D7DBFD13F9457F0E5DD365CB5D046B8C997058 +:153D0800DBF4E6772A5AE9026CF972B6B599E76FEB8B230DE54F +:153D1D005552CA5A7918F22A0ADC8A2FB46F9F30759E439A7424 +:153D3200501D4772753C7701753CA2AE8149D46F0EEB9317007C +:153D4700306C5F99FB57F2CF281AFD23F48FD23F46FF2DF48FD5 +:153D5C00D35FA77F8AFEA3F41FFF9919976DED36EB6A9EF9E018 +:153D71006E7D867B74863B3DC33D39C32DBD36DD1D9CE18ECEF0 +:153D8600706F99E1D667B8475FCB3B9342F86913A6DBB78880A5 +:153D9B0076BED19C5DB049AA97BFEBB85ACACF365BF9548E74A6 +:153DB000626D684D6C43D87F7258AFBD083A4DE14D21F726FA49 +:153DC5006FA37F92FE7DF41FA1FF09FA9FA1FF65FA4FD0FFC613 +:153DDA0045332E3B36CCF196B2E94F6EE04DCF73036FF13C37CD +:153DEF00F0B625CF0DBCC5F2DCC05B34CF0DBC45F2DCC05B3084 +:153E0400CF0DBCC9F9E5BF36657F93974F6E7F73CA006F433FFD +:153E19005A7C62C33DB67D048EB3D9EC7F107E3D2C0FBF33E3C5 +:153E2E00FC33C3D1F78C91FC42B2947E7A0E734357B658165B92 +:153E4300FA04E676D137F5332D1E1A238BE5459FBD48E36205B5 +:153E58007D838EA2B44BDD5C467DD65C56F218AB6989CC35FBFF +:153E6D00B407E83B3CD7ECCB2A59CD725BFF49869D72DCFB4582 +:153E820079006793A5347E53FA8952C80E2F4ED9E92019F152A8 +:153E970055178DCB872123E8932B9CCB4F531CB96CF6F1C91EC9 +:153EAC00E7B0378FF1689299363AEC781E2A77A7659780E49DE9 +:153EC100E597292F3797F7A7F7631504EF7609E321E48BDDFA81 +:153ED6009E18CEA5BDA8EF881CE6F5777FC6D92EC9753AFA7C2A +:153EEB009C112A5B79006BB9DA9639D89F1AD499FEA2EE178621 +:153F0000D516D6CDE377BB87156141138DAD83460DD54D243929 +:153F150097DB268FEED52ECEC538A6774A65499EC7988764486F +:153F2A004AE3925FD4451A8BDDA558571EA4BEFC450378AE91FA +:153F3F004CF903B0A63DD3E5BB9139ACE434E5979A8371A6469B +:153F54004FF0B1A9968F4D380F2B2C08727B0A976F66DDC5F1B1 +:153F6900AE1667B45695E56AFD8D15C2F2CD94E6CC5C5326B23D +:153F7E00F1E0B5740FA7F477653D4EBC29A57772BB7EC85FBA96 +:153F9300F02905E78C00B33732B854245945A43C2729CF769297 +:153FA800A9708E49E4BAD87C1C862D490379A0BD8BB161C323AE +:153FBD009BF7BA66B91EFF8B9A9FFA7C51FE9E81F8B8FB976419 +:153FD200B00D1305243FE3CEC7BCFBA71294C7DFC588F762B02A +:153FE700B561DA75FFCF6CB0C5436E8C33C065A498B9DF269E84 +:153FFC007D8B75B5D8B09B3819E17D13F2E0677ED892161BEE59 +:15401100EB0437F45D890E25B02303DE100907176F64DDF6BD19 +:1540260005F9750AE4D5C91E6F502FAEB740FD1DE0728ED39C6C +:15403B00233AA6F13A4883FD34F7A07AEF9EB2731CEBD27ADD53 +:15405000CCBD8660B5D37C2ED2DD029D8B9F1CF9E5618F5C6F8D +:15406500F8B9AEB24A6D76B561C32ECA87F9BC0DDF18E3250BE4 +:15407A00476B2D386D3D4E0B977EEC15D7539837262EF7154C5C +:15408F00B50DC95DA39AF7EBF6F1F28C5343CB59380C1D8CAC5D +:1540A400B96796CD7EEB5498FC123AEE46294B3FA9965DB84765 +:1540B900914EAD542B65472BD7C94EEF864E94DB9D3F6E5A70DC +:1540CE0036B0257C5C1E7531F715AAE32F88F7D8D6E7795E88FB +:1540E300EF425F1F1EE2F7AEF0F34BADF5FCDC0EC9E1FA77E3C0 +:1540F800832D38D303FC3E8D7B0B49A6B5F0EEF5669C2DF321EE +:15410D00AF674EEAD71F7C69F92FC88D3A8B99E1D9F98D706485 +:15412200F29BC93F9ECC71FD40C6D91E681DE6E5A19D99F4946F +:15413700394EEDFE5A6C5D82B51884EB95E38361BBBE51613A5F +:15414C005F42CFE6664C6801DC36DEDE1C1FE27D8027467D8299 +:1541610055CE2F288F8F5AA7CA8C7379B0783A2FB6BD9D75AFA9 +:15417600263A7A62797591BFA7439F3257179AC398F5AFCDD556 +:15418B00057088AD9FE675E1788A0D7E209E9C528D6AAD9364C6 +:1541A000515FD7A9FD5C671573A30187D54F100EA84F77E7EEE2 +:1541B5004C487769E7FE68EB0FD7F33A411FDC4EFB08A503BD44 +:1541CA00FB284D7E3FB3ED7D935F3DF2615D8E0D695F8F0C8732 +:1541DF0050367851DA3E669E8B4C0FD37CA11BFB9D567D877409 +:1541F400BBAD88992386E41E56CBA8CF3D48732B4F06FD8A6685 +:15420900D5FFC454FD892FE6B79EE4F59F4F74B3E89B1B438A6B +:15421E00D1DFF1F6A0C1DE7FAE3DDC840D9FF0B169EDE1B7E3CD +:15423300C7B85D1FE0ACE121D35E01CA798EED6D215E36DB49B7 +:154248006BB7C9C7046B4F1C67F0F5CE03B8B3217A7206BD7508 +:15425D0093DE5563CB0D727B624379743DA623CD145D87AC7ADB +:154272002579BDD0E794B5EEE5755A98129783F76D5AE6F89743 +:15428700FCC414EE0A49E83DD4FECC7B42CC7AFC35F1A7CD8B26 +:15429C005E36D6524AE503961B04CB42E2BD6345D379EFDCFF00 +:1542B10026BE93F3E08B117CB13CF8641B3EB35FE2F86CEDE6C9 +:1542C600F0E5F70BF1EBA6CE03DE62CCBC07588F24B694E68D22 +:1542DB0039F1776D5ECACD5DBD2CDCCB710B5B2C7D93D9921C44 +:1542F000EF916CF32B9C55785EBC478A99F36F6FE4B0FA32A58C +:15430500F1578BED6517FA1487C0CAE6212C7D4C972EA414DCF3 +:15431A00F17094609530E610FF6C06AFBA20776A5A2070A253C4 +:15432F00261929FE646FFB0EF827DF411FBEC375EE24D7DB9887 +:15434400A8DABB8CA5C7742328B4239FCAC45ED89CF3CDC7FD16 +:1543590068E49FC07AB5B4D710293FECCD7337952BF23DC1BDA2 +:15436E00064F87B2F4BDD07F9E87BB95BBCC343BE234A7C7BA03 +:15438300886BAD063D0E3FD7A1B3E6F412BF4F604CDFD9A6299D +:1543980005EBAEABF16CD6DBFB794D419D454A539938B201F0C4 +:1543AD0063EC042C80CD4F75692218FC174E28F36354D7B3DF2C +:1543C20056BD4CA33E3CA57C1FE38295A77876402519D88B7446 +:1543D70076DD7B28FFE4BEE3FC1E66F00B8F1B3DB6C3B5FB1DAF +:1543EC003503D8A84EA80BBB3EA0812EC003D34F6AC06723D44E +:154401005C28DCC6C5E51C1ECCB27278C07A6DDAC443E08762E3 +:154416004B721D742486B52EF2EF457B219CC00F6B1B18834D1B +:15442B00784F120E8E28C8BF60DDEFD5ED1C0F479432AA1F70F9 +:1544400020E15C15D5DB853B83A82CD84C0E52F99581894EDBE9 +:154455001EB2699F27AEE9C4837B162495B7D884B628C8FEB2C2 +:15446A0046163F97B3D7F917DC1E32B79BD4C6D70896F49B67EE +:15447F005B933C5D24B30B7756B8E98D7D6023F6EE149FE33C0E +:1544940023D6AAC0A3F5984B439736D8A4E937B89E663F8DB948 +:1544A900E3F15A67BBE00AAB623CA40E10AC55CA28EEB9D475D6 +:1544BE00F9402B9F9F521C89FA0E8FFCC51697FCB51649FED26B +:1544D30072312A63BC1EBF4AF230DE9D984B455FE43695FDCD24 +:1544E800B261E60F9971703C4861F594BE96D2D7507AF855C8F3 +:1544FD005F6AB1F3207E6AF150B88BC2AFAEF81ACFCFC3E766D2 +:15451200BFDB61C7D9827208265FF3A499B76EC20D1C85D136AC +:1545270008CE7AF9D556B1396864281CEB05AD349F1692215583 +:15453C008A630FD88C8FFC8807FC22E58378FC7C020EA4C7CC33 +:15455100FB80D0869B9835BF06CF4B435639239DB02952CE6D45 +:154566004F987E9833C18FEB1B9A67316E992F098249CF9C3FD4 +:15457B00E55F61CF7FB85E2A95CFEF384B195BDEBD75CE659ECD +:154590007D1DD11186FE07772CF8ADFEC69FFE8EEABBF01D0521 +:1545A500F2AAAFF59879AF1085F930F767C731BE6BAFFCB680E3 +:1545BA00558C1F6FDC42E39EC79A67983AB0A69C833B095CF13E +:1545CF00234BE793ECE943BEC111138E5C3F99E4F0F9228930CA +:1545E400B76F426EE4591E196AACC8CB333777A13E97A7B7FA20 +:1545F900CFDF5AFC8C7A606E47B079AFF2359D9AA934F9E76932 +:15460E00F9FDE74F69FF384BBAC333D211BFEBB3AD27453287BE +:15462300B4FF394BFACD1F21FDB559D2856F0BEF216D6296747F +:15463800EFB1DB9737F9FE8CFD27ACEFE4F31FD6FCDF9DBEBE22 +:15464D0031335CFAC38787C76F17FE7F3BFF19E19E7CFEFFB008 +:15466200F581FF1FFE4F0A97F2F0EF9DD92FFD3F03BFC51FD198 +:154677008F971EED6B9E287359ECCBDC46536D67B7147B641541 +:15468C0035454FD9A3AA46E1B82BDA73EF6E15ED14E3A4A76CC6 +:1546A100933A67F56E55961FD7E6DCDBA5FAD6698A47A8567DC5 +:1546B600A5D56A82E416AB4D6FB84163B35456AB22BF7F6A5E9C +:1546CB0087EED314EC110BEB30778969D0A813E582F6AF539F69 +:1546E000ECF754ABC5EBEAD5E7EEAB53AAD6D52901CF236A774F +:1546F500C1A714DCC5B8488CD973151FE28BC22754BEF6B0BABF +:15470A008BF71DE843AA4A130AF413ED702F0FAF539D65712E7A +:15471F00DF553D1057F9FE1264E459605865C15042301C22180D +:15473400FC79E5A3DC4A8201F178BE947F7ED937AC7C27F3F2CE +:15474900CD665FC97A60EB20C4DAD7331640DEF18298067C644E +:15475E009999D7DD8CCD9B4FB8F15099EEB57584A36A6591A745 +:154773005EADF88CD8EE645D1D557F25B61F9A9BE034C0BA4825 +:1547880090E0C01EDC5DDC76DA14EC5EAE07833DB8F813BC6EA9 +:15479D0004D3390BA631D4DD73BF5AB56FBD2A94DAB0656FDA01 +:1547B200B0B5106CE59E6AEE1F2701D1A697BBB45EF5709876A1 +:1547C7002B8B4A13EAFE9D7B72BC003CFF219BB56060BC9EB026 +:1547DC000966EE374F3E8172D3161CB81FEC0C7DCFD54C18CA91 +:1547F100F6D5A865541EEAD66E9D4D81D226C74BD1145EAA8851 +:15480600774AD6B6AAFE75610ECFAE82DD4A31E1A5C493500B35 +:15481B0059A2638FC59B8B79DDA7CA9DA0B2740A2B237C11DDC4 +:15483000BD360CA07D55DBFD0A64A1AA75F72B33E94F8DA8AC8E +:1548450098EF1B4CB5A7AA33033C9E70BE5EF53F105345F6B844 +:15485A003A87E23E27B080D3FA36E8BB641DC149FC52521A56D0 +:15486F00B51F352B87CE362B25E7D7AA7E8DFCF6AD56B5CFAF8A +:1548840021DE5FA38007FC84D3AAB5262EC498D02EB34D9CB7E4 +:15489900494EF3398587544FAC0077EBF8DCD8ABA96CEB9C2374 +:1548AE003CAC7AC455AA67259577EF63AA67F51A756FC12A05F2 +:1548C300FA1EE2CAA9F84501F31C188F9F0899F15FFEAAEA3924 +:1548D800DDACEEDD19529C34EE96FDE811A5EA3305EDB0BDEDB4 +:1548ED008A873ADCE3CD1D07610F4D0BA955E71F528573CDAA2E +:15490200467105D7142DB6A28D07F8B9B10DB005E4EAA274A731 +:154917009A3BF85CAF89B51796053B8ACA9A3AAA92EB955DD473 +:15492C0037C8E4DF43EFBF449FF3F71B554F4FB30AB95A961F63 +:15494100866CE7F224BEAA0A6B1F5779D8CBCD141E52F712CEDB +:15495600407FF038E624C5FF5168AF3A4F38D4BA54FFF9AFAA3B +:15496B0025E776731ED84F3C3087685F1CD13AF2FB25D01DB469 +:15498000E33AF5164DC193F7122CED809FF08CBB49D7D177A2D7 +:1549950060B33287CA01FCDD3BCDEF5537B37EF44BB61B7169FF +:1549AA006CD83090C51A8EC9DB064DAD803FF47B34E79A67F3A6 +:1549BF00D5368AC3CF47100C9B67E80797FDA842A93A574EB8AA +:1549D4002D5767E3A337D9141FFD9A997C041A14131F053C9B2E +:1549E900395E9EB378097CE4D7C86F062FED8EFFF9C6E2C026AC +:1549FE00A24FAC73377B78E39C40B453F03CA6DAEE92C8C31BD2 +:154A130041A7395DEB3BD8D9F60EFB5D75CDC1EF702A8EAFEF25 +:154A280028196FEF10DC44F34F546B4EA2C34DA23DF07737A785 +:154A3D0085A3BD44DB4174788CE8B087F7E9F9B428B0689130FA +:154A5200EF8EF209AE4F50D9D10D67385DC037D10D6333E84242 +:154A670034F13E60D185FA5DEFFA3CBADC994797B7B8CEEF5418 +:154A7C00DBDE49EDBA378F4EDCFE38F100FCB75BB4BA803BFF2F +:154A91002CDA6CFA98F4B894478FBFB3E88136EDB768710B1D40 +:154AA6008836F9B4288A7C65636164FD46B68DB57BC6BFD23197 +:154ABB0047DAD451C4FECDC6E2F8BFEDF08C3FCCDD557FC5DBED +:154AD000ABD7C3C81D799CE35DDC5EAD39A8EFBD5914D58A6DA5 +:154AE500BC533B2DF1ECA4FEEF5FA9256B9F9C86F7E2D9F09E3E +:154AFA005C0C9AE7E13DC6F16ED7371FFFD4E77BEFB5F08F35C1 +:154B0F0011B4131BFFDE3CFC3BF8DA8689DF5E0BBFA5E8A7280A +:154B2400AC92E65AF96DC04EFF261F174C9A211DE8A658743081 +:154B3900711E9E06CBB708CF9E94D0FE32BD13D4F714521EB8D2 +:154B4E00FFFDD0171F51ABD6B52A52C152A5A8E01E053CECA121 +:154B6300BE879D6DEE38F4530A3BBF56F1167C5E71177CC10C75 +:154B7800135675B0FBD674EC8A39DA01D762E084CA261E292BCC +:154B8D00941D7C8C843FECB9D87314940FBBA705F6D86D8D1FA2 +:154BA20088075D7FC0F55A36EBA338B9B6FF32B57D8C5D9768CE +:154BB7003A89F512C80734D6F94E5BF1BF4FDF55D744BCBD27B6 +:154BCC00785E4975BF63E8117EC65230EF62A69125EB8D0C3DF1 +:154BE1006A308DEB88C1DF37B5DE5AFC7F00E871AED038A00037 +:014BF60000BE +:00000001FF diff -u --recursive --new-file v2.3.47/linux/drivers/atm/zatm.c linux/drivers/atm/zatm.c --- v2.3.47/linux/drivers/atm/zatm.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/atm/zatm.c Mon Feb 21 16:32:27 2000 @@ -636,12 +636,12 @@ event_dump(); } if (!size) { - kfree_skb(skb); + dev_kfree_skb_irq(skb); if (vcc) vcc->stats->rx_err++; continue; } if (!atm_charge(vcc,skb->truesize)) { - kfree_skb(skb); + dev_kfree_skb_irq(skb); continue; } skb->len = size; @@ -854,7 +854,7 @@ uPD98401_TXBD_SIZE*ATM_SKB(skb)->iovcnt,GFP_ATOMIC); if (!dsc) { if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_irq(skb); return -EAGAIN; } /* @@@ should check alignment */ @@ -908,7 +908,7 @@ *ZATM_PRV_DSC(skb) = 0; /* mark as invalid */ zatm_vcc->txing--; if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); + else dev_kfree_skb_irq(skb); while ((skb = skb_dequeue(&zatm_vcc->backlog))) if (do_tx(skb) == RING_BUSY) { skb_queue_head(&zatm_vcc->backlog,skb); @@ -1395,7 +1395,7 @@ command | PCI_COMMAND_IO | PCI_COMMAND_MASTER))) { printk(KERN_ERR DEV_LABEL "(itf %d): can't enable IO (0x%02x)" "\n",dev->number,error); - return error; + return -EIO; } eprom_get_esi(dev); printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,", @@ -1741,7 +1741,6 @@ if (!skb) { printk(KERN_CRIT "!skb in zatm_send ?\n"); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); return -EINVAL; } ATM_SKB(skb)->vcc = vcc; diff -u --recursive --new-file v2.3.47/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.3.47/linux/drivers/block/Config.in Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/Config.in Sat Feb 26 20:32:13 2000 @@ -44,6 +44,7 @@ bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then + bool ' Sharing PCI IDE interrupts support' CONFIG_IDEPCI_SHARE_IRQ bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA_PCI if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO @@ -54,38 +55,43 @@ define_bool CONFIG_IDEDMA_PCI_EXPERIMENTAL n fi fi + if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then + bool ' ATA Work(s) In Progress (EXPERIMENTAL)' CONFIG_IDEDMA_PCI_WIP + fi bool ' Boot off-board chipsets first support' CONFIG_BLK_DEV_OFFBOARD bool ' AEC6210 chipset support' CONFIG_BLK_DEV_AEC6210 - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then - bool ' AEC6210 Tuning support (EXPERIMENTAL)' CONFIG_BLK_DEV_AEC6210_TUNING + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_AEC6210" = "y" ]; then + bool ' AEC6210 Tuning support (WIP)' CONFIG_AEC6210_TUNING fi if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' ALI M15x3 chipset support' CONFIG_BLK_DEV_ALI15X3 - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - bool ' AMD Viper support (EXPERIMENTAL)' CONFIG_BLK_DEV_AMD7409 + bool ' AMD Viper support' CONFIG_BLK_DEV_AMD7409 + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_AMD7409" = "y" ]; then + bool ' AMD Viper ATA-66 Override (WIP)' CONFIG_AMD7409_OVERRIDE fi fi bool ' CMD64X chipset support' CONFIG_BLK_DEV_CMD64X - if [ "$CONFIG_BLK_DEV_CMD64X" = "y" -a "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then - bool ' CMD64X chipset RAID support (EXPERIMENTAL) (WIP)' CONFIG_BLK_DEV_CMD64X_RAID + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_CMD64X" = "y" ]; then + bool ' CMD64X chipset RAID (WIP)' CONFIG_CMD64X_RAID fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' CY82C693 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CY82C693 fi + bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' HPT34X chipset support' CONFIG_BLK_DEV_HPT34X - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then - bool ' HPT34X DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_HPT34X_DMA + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_HPT34X" = "y" ]; then + bool ' HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA fi bool ' HPT366 chipset support' CONFIG_BLK_DEV_HPT366 - if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then - bool ' HPT366 Fast Interrupt support (EXPERIMENTAL) (WIP)' CONFIG_HPT366_FAST_IRQ_PREDICTION - bool ' HPT366 mode three unsupported (EXPERIMENTAL) (WIP)' CONFIG_HPT366_MODE3 + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" -a "$CONFIG_BLK_DEV_HPT366" = "y" ]; then + bool ' HPT366 Fast Interrupts (WIP)' CONFIG_HPT366_FIP + bool ' HPT366 mode Three (WIP)' CONFIG_HPT366_MODE3 fi - if [ "$CONFIG_X86" = "y" ]; then + if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then bool ' Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX if [ "$CONFIG_BLK_DEV_PIIX" = "y" -a "$CONFIG_IDEDMA_PCI_AUTO" = "y" ]; then - bool ' PIIXn Tuning support' CONFIG_BLK_DEV_PIIX_TUNING + bool ' PIIXn Tuning support' CONFIG_PIIX_TUNING fi fi fi @@ -98,21 +104,18 @@ if [ "$CONFIG_BLK_DEV_IDEDMA_PCI" = "y" ]; then bool ' PROMISE PDC20246/PDC20262 support' CONFIG_BLK_DEV_PDC202XX if [ "$CONFIG_BLK_DEV_PDC202XX" = "y" ]; then - bool ' Special UDMA Feature' CONFIG_PDC202XX_FORCE_BURST_BIT - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' Special Mode Feature (EXPERIMENTAL)' CONFIG_PDC202XX_FORCE_MASTER_MODE + bool ' Special UDMA Feature' CONFIG_PDC202XX_BURST + if [ "$CONFIG_IDEDMA_PCI_WIP" = "y" ]; then + bool ' Special Mode Feature (WIP)' CONFIG_PDC202XX_MASTER fi fi if [ "$CONFIG_X86" = "y" ]; then bool ' SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 fi - bool ' Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 fi if [ "$CONFIG_IDEDMA_PCI_EXPERIMENTAL" = "y" ]; then bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 - if [ "$CONFIG_X86" = "y" ]; then - bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX - fi + bool ' VIA82CXXX chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82CXXX fi fi if [ "$CONFIG_PPC" = "y" -o "$CONFIG_ARM" = "y" ]; then @@ -232,6 +235,7 @@ "$CONFIG_BLK_DEV_AMD7409" = "y" -o \ "$CONFIG_BLK_DEV_CMD640" = "y" -o \ "$CONFIG_BLK_DEV_CMD64X" = "y" -o \ + "$CONFIG_BLK_DEV_CS5530" = "y" -o \ "$CONFIG_BLK_DEV_CY82C693" = "y" -o \ "$CONFIG_BLK_DEV_HPT34X" = "y" -o \ "$CONFIG_BLK_DEV_HPT366" = "y" -o \ @@ -240,7 +244,6 @@ "$CONFIG_BLK_DEV_PDC202XX" = "y" -o \ "$CONFIG_BLK_DEV_PIIX" = "y" -o \ "$CONFIG_BLK_DEV_SIS5513" = "y" -o \ - "$CONFIG_BLK_DEV_CS5530" = "y" -o \ "$CONFIG_BLK_DEV_SL82C105" = "y" ]; then define_bool CONFIG_BLK_DEV_IDE_MODES y else diff -u --recursive --new-file v2.3.47/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.3.47/linux/drivers/block/Makefile Sun Feb 20 21:12:38 2000 +++ linux/drivers/block/Makefile Sat Feb 26 20:32:13 2000 @@ -130,6 +130,10 @@ IDE_OBJS += cmd64x.o endif +ifeq ($(CONFIG_BLK_DEV_CS5530),y) +IDE_OBJS += cs5530.o +endif + ifeq ($(CONFIG_BLK_DEV_CY82C693),y) IDE_OBJS += cy82c693.o endif @@ -196,10 +200,6 @@ ifeq ($(CONFIG_BLK_DEV_PDC202XX),y) IDE_OBJS += pdc202xx.o -endif - -ifeq ($(CONFIG_BLK_DEV_CS5530),y) -IDE_OBJS += cs5530.o endif ifeq ($(CONFIG_BLK_DEV_PDC4030),y) diff -u --recursive --new-file v2.3.47/linux/drivers/block/README.buddha linux/drivers/block/README.buddha --- v2.3.47/linux/drivers/block/README.buddha Mon Aug 9 12:32:28 1999 +++ linux/drivers/block/README.buddha Wed Dec 31 16:00:00 1969 @@ -1,210 +0,0 @@ - -The Amiga Buddha and Catweasel IDE Driver (part of ide.c) was written by -Geert Uytterhoeven based on the following specifications: - ------------------------------------------------------------------------- - -Register map of the Buddha IDE controller and the -Buddha-part of the Catweasel Zorro-II version - -The Autoconfiguration has been implemented just as Commodore -described in their manuals, no tricks have been used (for -example leaving some address lines out of the equations...). -If you want to configure the board yourself (for example let -a Linux kernel configure the card), look at the Commodore -Docs. Reading the nibbles should give this information: - -Vendor number: 4626 ($1212) -product number: 0 (42 for Catweasel Z-II) -Serial number: 0 -Rom-vector: $1000 - -The card should be a Z-II board, size 64K, not for freemem -list, Rom-Vektor is valid, no second Autoconfig-board on the -same card, no space preferrence, supports "Shutup_forever". - -Setting the base address should be done in two steps, just -as the Amiga Kickstart does: The lower nibble of the 8-Bit -address is written to $4a, then the whole Byte is written to -$48, while it doesn't matter how often you're writing to $4a -as long as $48 is not touched. After $48 has been written, -the whole card disappears from $e8 and is mapped to the new -addrress just written. Make shure $4a is written befor $48, -otherwise your chance is only 1:16 to find the board :-). - -The local memory-map is even active when mapped to $e8: - -$0-$7e Autokonfig-space, see Z-II docs. - -$80-$7fd reserved - -$7fe Speed-select Register: Read & Write - (description see further down) - -$800-$8ff IDE-Select 0 (Port 0, Register set 0) - -$900-$9ff IDE-Select 1 (Port 0, Register set 1) - -$a00-$aff IDE-Select 2 (Port 1, Register set 0) - -$b00-$bff IDE-Select 3 (Port 1, Register set 1) - -$c00-$cff IDE-Select 4 (Port 2, Register set 0, - Catweasel only!) - -$d00-$dff IDE-Select 5 (Port 3, Register set 1, - Catweasel only!) - -$e00-$eff local expansion port, on Catweasel Z-II the - Catweasel registers are also mapped here. - Never touch, use multidisk.device! - -$f00 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 0. - -$f01-$f3f mirror of $f00 - -$f40 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 1. - -$f41-$f7f mirror of $f40 - -$f80 read only, Byte-access: Bit 7 shows the - level of the IRQ-line of IDE port 2. - (Catweasel only!) - -$f81-$fbf mirror of $f80 - -$fc0 write-only: Writing any value to this - register enables IRQs to be passed from the - IDE ports to the Zorro bus. This mechanism - has been implemented to be compatible with - harddisks that are either defective or have - a buggy firmware and pull the IRQ line up - while starting up. If interrupts would - always be passed to the bus, the computer - might not start up. Once enabled, this flag - can not be disabled again. The level of the - flag can not be determined by software - (what for? Write to me if it's necessary!). - -$fc1-$fff mirror of $fc0 - -$1000-$ffff Buddha-Rom with offset $1000 in the rom - chip. The addresses $0 to $fff of the rom - chip cannot be read. Rom is Byte-wide and - mapped to even addresses. - -The IDE ports issue an INT2. You can read the level of the -IRQ-lines of the IDE-ports by reading from the three (two -for Buddha-only) registers $f00, $f40 and $f80. This way -more than one I/O request can be handled and you can easily -determine what driver has to serve the INT2. Buddha and -Catweasel expansion boards can issue an INT6. A seperate -memory map is available for the I/O module and the sysop's -I/O module. - -The IDE ports are fed by the address lines A2 to A4, just as -the Amiga 1200 and Amiga 4000 IDE ports are. This way -existing drivers can be easily ported to Buddha. A move.l -polls two words out of the same address of IDE port since -every word is mirrored once. movem is not possible, but -it's not necessary either, because you can only speedup -68000 systems with this technique. A 68020 system with -fastmem is faster with move.l. - -If you're using the mirrored registers of the IDE-ports with -A6=1, the Buddha doesn't care about the speed that you have -selected in the speed register (see further down). With -A6=1 (for example $840 for port 0, register set 0), a 780ns -access is being made. These registers should be used for a -command access to the harddisk/CD-Rom, since command -accesses are Byte-wide and have to be made slower according -to the ATA-X3T9 manual. - -Now for the speed-register: The register is byte-wide, and -only the upper three bits are used (Bits 7 to 5). Bit 4 -must always be set to 1 to be compatible with later Buddha -versions (if I'll ever update this one). I presume that -I'll never use the lower four bits, but they have to be set -to 1 by definition. - The values in this table have to be shifted 5 bits to the -left and or'd with $1f (this sets the lower 5 bits). - -All the timings have in common: Select and IOR/IOW rise at -the same time. IOR and IOW have a propagation delay of -about 30ns to the clocks on the Zorro bus, that's why the -values are no multiple of 71. One clock-cycle is 71ns long -(exactly 70,5 at 14,18 Mhz on PAL systems). - -value 0 (Default after reset) - -497ns Select (7 clock cycles) , IOR/IOW after 172ns (2 clock cycles) -(same timing as the Amiga 1200 does on it's IDE port without -accelerator card) - -value 1 - -639ns Select (9 clock cycles), IOR/IOW after 243ns (3 clock cycles) - -value 2 - -781ns Select (11 clock cycles), IOR/IOW after 314ns (4 clock cycles) - -value 3 - -355ns Select (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) - -value 4 - -355ns Select (5 clock cycles), IOR/IOW after 172ns (2 clock cycles) - -value 5 - -355ns Select (5 clock cycles), IOR/IOW after 243ns (3 clock cycles) - -value 6 - -1065ns Select (15 clock cycles), IOR/IOW after 314ns (4 clock cycles) - -value 7 - -355ns Select, (5 clock cycles), IOR/IOW after 101ns (1 clock cycle) - -When accessing IDE registers with A6=1 (for example $84x), -the timing will always be mode 0 8-bit compatible, no matter -what you have selected in the speed register: - -781ns select, IOR/IOW after 4 clock cycles (=314ns) aktive. - -All the timings with a very short select-signal (the 355ns -fast accesses) depend on the accelerator card used in the -system: Sometimes two more clock cycles are inserted by the -bus interface, making the whole access 497ns long. This -doesn't affect the reliability of the controller nor the -performance of the card, since this doesn't happen very -often. - -All the timings are calculated and only confirmed by -measurements that allowed me to count the clock cycles. If -the system is clocked by an oscillator other than 28,37516 -Mhz (for example the NTSC-frequency 28,63636 Mhz), each -clock cycle is shortened to a bit less than 70ns (not worth -mentioning). You could think of a small performance boost -by overclocking the system, but you would either need a -multisync monitor, or a graphics card, and your internal -diskdrive would go crazy, that's why you shouldn't tune your -Amiga this way. - -Giving you the possibility to write software that is -compatible with both the Buddha and the Catweasel Z-II, The -Buddha acts just like a Catweasel Z-II with no device -connected to the third IDE-port. The IRQ-register $f80 -always shows a "no IRQ here" on the Buddha, and accesses to -the third IDE port are going into data's Nirwana on the -Buddha. - - Jens Schönfeld february 19th, 1997 - updated may 27th, 1997 - eMail: sysop@nostlgic.tng.oche.de - diff -u --recursive --new-file v2.3.47/linux/drivers/block/README.fd linux/drivers/block/README.fd --- v2.3.47/linux/drivers/block/README.fd Mon Dec 20 18:48:21 1999 +++ linux/drivers/block/README.fd Wed Dec 31 16:00:00 1969 @@ -1,222 +0,0 @@ -This Readme file describes the floppy driver. - -FAQ list: -========= - - A FAQ list may be found in the fdutils package (see below), and also -at http://fdutils.linux.lu/FAQ.html - - -LILO configuration options (Thinkpad users, read this) -====================================================== - - The floppy driver is configured using the 'floppy=' option in -lilo. This option can be typed at the boot prompt, or entered in the -lilo configuration file. - Example: If your kernel is called linux-2.2.13, type the following line -at the lilo boot prompt (if you have a thinkpad): - linux-2.2.13 floppy=thinkpad -You may also enter the following line in /etc/lilo.conf, in the description -of linux-2.2.13: - append = "floppy=thinkpad" - - Several floppy related options may be given, example: - linux-2.2.13 floppy=daring floppy=two_fdc - append = "floppy=daring floppy=two_fdc" - - If you give options both in the lilo config file and on the boot -prompt, the option strings of both places are concatenated, the boot -prompt options coming last. That's why there are also options to -restore the default behavior. - - If you use the floppy driver as a module, use the following syntax: - insmod floppy - -Example: - insmod floppy daring two_fdc - - Some versions of insmod are buggy in one way or another. If you have -any problems (options not being passed correctly, segfaults during -insmod), first check whether there is a more recent version. - - The floppy related options include: - - floppy=asus_pci - Sets the bit mask to allow only units 0 and 1. (default) - - floppy=daring - Tells the floppy driver that you have a well behaved floppy controller. - This allows more efficient and smoother operation, but may fail on - certain controllers. This may speed up certain operations. - - floppy=0,daring - Tells the floppy driver that your floppy controller should be used - with caution. - - floppy=one_fdc - Tells the floppy driver that you have only one floppy controller. - (default) - - floppy=two_fdc - floppy=
,two_fdc - Tells the floppy driver that you have two floppy controllers. - The second floppy controller is assumed to be at
. - This option is not needed if the second controller is at address - 0x370, and if you use the 'cmos' option. - - floppy=thinkpad - Tells the floppy driver that you have a Thinkpad. Thinkpads use an - inverted convention for the disk change line. - - floppy=0,thinkpad - Tells the floppy driver that you don't have a Thinkpad. - - floppy=omnibook - floppy=nodma - Tells the floppy driver not to use Dma for data transfers. - This is needed on HP Omnibooks, which don't have a workable - DMA channel for the floppy driver. This option is also useful - if you frequently get "Unable to allocate DMA memory" messages. - Indeed, dma memory needs to be continuous in physical memory, - and is thus harder to find, whereas non-dma buffers may be - allocated in virtual memory. However, I advise against this if - you have an FDC without a FIFO (8272A or 82072). 82072A and - later are OK. You also need at least a 486 to use nodma. - If you use nodma mode, I suggest you also set the FIFO - threshold to 10 or lower, in order to limit the number of data - transfer interrupts. - - If you have a FIFO-able FDC, the floppy driver automatically - falls back on non DMA mode if no DMA-able memory can be found. - If you want to avoid this, explicitely ask for 'yesdma'. - - floppy=yesdma - Tells the floppy driver that a workable DMA channel is available. - (default) - - floppy=nofifo - Disables the FIFO entirely. This is needed if you get "Bus - master arbitration error" messages from your Ethernet card (or - from other devices) while accessing the floppy. - - floppy=fifo - Enables the FIFO. (default) - - floppy=,fifo_depth - Sets the FIFO threshold. This is mostly relevant in DMA - mode. If this is higher, the floppy driver tolerates more - interrupt latency, but it triggers more interrupts (i.e. it - imposes more load on the rest of the system). If this is - lower, the interrupt latency should be lower too (faster - processor). The benefit of a lower threshold is less - interrupts. - To tune the fifo threshold, switch on over/underrun messages - using 'floppycontrol --messages'. Then access a floppy - disk. If you get a huge amount of "Over/Underrun - retrying" - messages, then the fifo threshold is too low. Try with a - higher value, until you only get an occasional Over/Underrun. - It is a good idea to compile the floppy driver as a module - when doing this tuning. Indeed, it allows to try different - fifo values without rebooting the machine for each test. Note - that you need to do 'floppycontrol --messages' every time you - re-insert the module. - Usually, tuning the fifo threshold should not be needed, as - the default (0xa) is reasonable. - - floppy=,,cmos - Sets the CMOS type of to . This is mandatory if - you have more than two floppy drives (only two can be - described in the physical CMOS), or if your BIOS uses - non-standard CMOS types. The CMOS types are: - 0 - Use the value of the physical CMOS - 1 - 5 1/4 DD - 2 - 5 1/4 HD - 3 - 3 1/2 DD - 4 - 3 1/2 HD - 5 - 3 1/2 ED - 6 - 3 1/2 ED - 16 - unknown or not installed - (Note: there are two valid types for ED drives. This is because 5 was - initially chosen to represent floppy *tapes*, and 6 for ED drives. - AMI ignored this, and used 5 for ED drives. That's why the floppy - driver handles both.) - - floppy=unexpected_interrupts - Print a warning message when an unexpected interrupt is received. - (default) - - floppy=no_unexpected_interrupts - floppy=L40SX - Don't print a message when an unexpected interrupt is received. This - is needed on IBM L40SX laptops in certain video modes. (There seems - to be an interaction between video and floppy. The unexpected - interrupts affect only performance, and can be safely ignored.) - - floppy=broken_dcl - Don't use the disk change line, but assume that the disk was - changed whenever the device node is reopened. Needed on some - boxes where the disk change line is broken or unsupported. - This should be regarded as a stopgap measure, indeed it makes - floppy operation less efficient due to unneeded cache - flushings, and slightly more unreliable. Please verify your - cable, connection and jumper settings if you have any DCL - problems. However, some older drives, and also some laptops - are known not to have a DCL. - - floppy=debug - Print debugging messages. - - floppy=messages - Print informational messages for some operations (disk change - notifications, warnings about over and underruns, and about - autodetection). - - floppy=silent_dcl_clear - Uses a less noisy way to clear the disk change line (which - doesn't involve seeks). Implied by 'daring' option. - - floppy=,irq - Sets the floppy IRQ to instead of 6. - - floppy=,dma - Sets the floppy DMA channel to instead of 2. - - floppy=slow - Use PS/2 stepping rate: - " PS/2 floppies have much slower step rates than regular floppies. - It's been recommended that take about 1/4 of the default speed - in some more extreme cases." - - - -Supporting utilities and additional documentation: -================================================== - - Additional parameters of the floppy driver can be configured at -runtime. Utilities which do this can be found in the fdutils package. -This package also contains a new version of mtools which allows to -access high capacity disks (up to 1992K on a high density 3 1/2 disk!). -It also contains additional documentation about the floppy driver. - -The latest version can be found at fdutils homepage: - http://fdutils.linux.lu - -The fdutils-5.3 release can be found at: - http://fdutils.linux.lu/fdutils-5.3.src.tar.gz - http://www.tux.org/pub/knaff/fdutils/fdutils-5.3.src.tar.gz - ftp://tsx-11.mit.edu/pub/linux/sources/sbin/fdutils-5.3.src.tar.gz - ftp://metalab.unc.edu/pub/Linux/utils/disk-management/fdutils-5.3.src.tar.gz - -Reporting problems about the floppy driver -========================================== - - If you have a question or a bug report about the floppy driver, mail -me at Alain.Knaff@poboxes.com . If you post to Usenet, preferably use -comp.os.linux.hardware. As the volume in these groups is rather high, -be sure to include the word "floppy" (or "FLOPPY") in the subject -line. If the reported problem happens when mounting floppy disks, be -sure to mention also the type of the filesystem in the subject line. - - Be sure to read the FAQ before mailing/posting any bug reports! - - Alain diff -u --recursive --new-file v2.3.47/linux/drivers/block/README.lvm linux/drivers/block/README.lvm --- v2.3.47/linux/drivers/block/README.lvm Sun Feb 20 21:12:38 2000 +++ linux/drivers/block/README.lvm Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ - -This is the Logical Volume Manager driver for Linux, - -Tools, library that manage logical volumes can be found -at . - -There you can obtain actual driver versions too. - diff -u --recursive --new-file v2.3.47/linux/drivers/block/README.md linux/drivers/block/README.md --- v2.3.47/linux/drivers/block/README.md Tue Jun 11 03:00:11 1996 +++ linux/drivers/block/README.md Wed Dec 31 16:00:00 1969 @@ -1,4 +0,0 @@ -Tools that manage md devices can be found at sweet-smoke.ufr-info-p7.ibp.fr -in public/Linux/md035.tar.gz. - - Marc ZYNGIER diff -u --recursive --new-file v2.3.47/linux/drivers/block/aec6210.c linux/drivers/block/aec6210.c --- v2.3.47/linux/drivers/block/aec6210.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/aec6210.c Sat Feb 26 20:32:13 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/aec6210.c Version 0.04 Dec. 13, 1999 + * linux/drivers/block/aec6210.c Version 0.05 Feb. 10, 2000 * - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * pio 0 :: 40: 00 07 00 00 00 00 00 00 02 07 a6 04 00 02 00 02 @@ -56,7 +56,52 @@ #define ACARD_DEBUG_DRIVE_INFO 1 -#ifdef CONFIG_BLK_DEV_AEC6210_TUNING +#define DISPLAY_AEC6210_TIMINGS + +#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int aec6210_get_info(char *, char **, off_t, int); +extern int (*aec6210_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int aec6210_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + p += sprintf(p, "\n AEC6210 Chipset.\n"); + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + return p-buffer;/* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte aec6210_proc = 0; + +#ifdef CONFIG_AEC6210_TUNING struct chipset_bus_clock_list_entry { byte xfer_speed; @@ -269,7 +314,7 @@ } return ide_dmaproc(func, drive); /* use standard DMA stuff */ } -#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */ +#endif /* CONFIG_AEC6210_TUNING */ unsigned int __init pci_init_aec6210 (struct pci_dev *dev, const char *name) { @@ -277,12 +322,19 @@ pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } + +#if defined(DISPLAY_AEC6210_TIMINGS) && defined(CONFIG_PROC_FS) + aec6210_proc = 1; + bmide_dev = dev; + aec6210_display_info = &aec6210_get_info; +#endif /* DISPLAY_AEC6210_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } void __init ide_init_aec6210 (ide_hwif_t *hwif) { -#ifdef CONFIG_BLK_DEV_AEC6210_TUNING +#ifdef CONFIG_AEC6210_TUNING hwif->tuneproc = &aec6210_tune_drive; if (hwif->dma_base) { @@ -291,7 +343,7 @@ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } -#endif /* CONFIG_BLK_DEV_AEC6210_TUNING */ +#endif /* CONFIG_AEC6210_TUNING */ } void __init ide_dmacapable_aec6210 (ide_hwif_t *hwif, unsigned long dmabase) diff -u --recursive --new-file v2.3.47/linux/drivers/block/ali14xx.c linux/drivers/block/ali14xx.c --- v2.3.47/linux/drivers/block/ali14xx.c Thu Nov 18 20:25:37 1999 +++ linux/drivers/block/ali14xx.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996 + * linux/drivers/block/ali14xx.c Version 0.03 Feb 09, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ @@ -55,12 +55,12 @@ /* port addresses for auto-detection */ #define ALI_NUM_PORTS 4 -static int ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4}; +static int __init ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4}; /* register initialization data */ typedef struct { byte reg, data; } RegInitializer; -static RegInitializer initData[] = { +static RegInitializer __init initData[] = { {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, @@ -150,7 +150,7 @@ /* * Auto-detect the IDE controller port. */ -static int findPort (void) +static int __init findPort (void) { int i; byte t; @@ -183,7 +183,7 @@ /* * Initialize controller registers with default values. */ -static int initRegisters (void) { +static int __init initRegisters (void) { RegInitializer *p; byte t; unsigned long flags; @@ -200,7 +200,7 @@ return t; } -void init_ali14xx (void) +void __init init_ali14xx (void) { /* auto-detect IDE controller port */ if (!findPort()) { diff -u --recursive --new-file v2.3.47/linux/drivers/block/alim15x3.c linux/drivers/block/alim15x3.c --- v2.3.47/linux/drivers/block/alim15x3.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/alim15x3.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000 + * linux/drivers/block/alim15x3.c Version 0.08 Jan. 14, 2000 * * Copyright (C) 1998-2000 Michel Aubry, Maintainer * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer @@ -493,7 +493,6 @@ default: break; } - return ide_dmaproc(func, drive); /* use standard DMA stuff */ } @@ -518,6 +517,13 @@ if (inb(fixdma_base+2) & 0x80) printk("%s: simplex device: DMA will fail!!\n", name); } + +#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) + ali_proc = 1; + bmide_dev = dev; + ali_display_info = &ali_get_info; +#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ + return 0; } @@ -666,22 +672,11 @@ */ hwif->dmaproc = &ali15x3_dmaproc; hwif->autodma = 1; - hwif->drives[0].autotune = 0; - hwif->drives[1].autotune = 0; } else { hwif->autodma = 0; hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } - -#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) - if (!ali_proc) { - ali_proc = 1; - bmide_dev = hwif->pci_dev; - ali_display_info = &ali_get_info; - } -#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ - return; } diff -u --recursive --new-file v2.3.47/linux/drivers/block/amd7409.c linux/drivers/block/amd7409.c --- v2.3.47/linux/drivers/block/amd7409.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/amd7409.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/amd7409.c Version 0.01 Jan. 10, 2000 + * linux/drivers/block/amd7409.c Version 0.03 Feb. 10, 2000 * * Copyright (C) 2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -24,6 +24,51 @@ #include "ide_modes.h" +#define DISPLAY_VIPER_TIMINGS + +#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int amd7409_get_info(char *, char **, off_t, int); +extern int (*amd7409_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int amd7409_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n AMD 7409 VIPER Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte amd7409_proc = 0; + +extern char *ide_xfer_verbose (byte xfer_rate); + /* * Here is where all the hard work goes to program the chipset. * @@ -33,11 +78,13 @@ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; int err = 0; - int drive_number = ((HWIF(drive)->channel ? 2 : 0) + - (drive->select.b.unit & 0x01)); + byte unit = (drive->select.b.unit & 0x01); + int drive_number = ((HWIF(drive)->channel ? 2 : 0) + unit); + unsigned long dma_base = hwif->dma_base; byte drive_pci = 0x00; byte drive_pci2 = 0x00; - byte drive_timing = 0x00; + byte ultra_timing = 0x00; + byte dma_pio_timing = 0x00; byte pio_timing = 0x00; switch (drive_number) { @@ -49,54 +96,99 @@ return ((int) ide_dma_off_quietly); } - pci_read_config_byte(dev, drive_pci, &drive_timing); - pci_read_config_byte(dev, drive_pci2, &pio_timing); + pci_read_config_byte(dev, drive_pci, &ultra_timing); + pci_read_config_byte(dev, drive_pci2, &dma_pio_timing); + pci_read_config_byte(dev, 0x4c, &pio_timing); + +#ifdef DEBUG + printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", + drive->name, ultra_timing, dma_pio_timing, pio_timing); +#endif - printk("%s: UDMA 0x%02x PIO 0x%02x ", - drive->name, drive_timing, pio_timing); + ultra_timing &= ~0xC7; + dma_pio_timing &= ~0xFF; + pio_timing &= ~(0x03 << drive_number); + +#ifdef DEBUG + printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ", + ultra_timing, dma_pio_timing, pio_timing); +#endif switch(speed) { case XFER_UDMA_4: - drive_timing &= ~0xC7; - drive_timing |= 0x45; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x45; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_3: - drive_timing &= ~0xC7; - drive_timing |= 0x44; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x44; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_2: - drive_timing &= ~0xC7; - drive_timing |= 0x40; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x40; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_1: - drive_timing &= ~0xC7; - drive_timing |= 0x41; - pci_write_config_byte(dev, drive_pci, drive_timing); + ultra_timing |= 0x41; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); break; case XFER_UDMA_0: - drive_timing &= ~0xC7; - drive_timing |= 0x42; - pci_write_config_byte(dev, drive_pci, drive_timing); - break; - case XFER_MW_DMA_2:break; - case XFER_MW_DMA_1:break; - case XFER_MW_DMA_0:break; - case XFER_SW_DMA_2:break; - case XFER_SW_DMA_1:break; - case XFER_SW_DMA_0:break; - case XFER_PIO_4:break; - case XFER_PIO_3:break; - case XFER_PIO_2:break; - case XFER_PIO_1:break; - case XFER_PIO_0:break; - default: break; + ultra_timing |= 0x42; + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); + break; + case XFER_MW_DMA_2: + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); + break; + case XFER_MW_DMA_1: + dma_pio_timing |= 0x21; + pio_timing |= (0x03 << drive_number); + break; + case XFER_MW_DMA_0: + dma_pio_timing |= 0x77; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_4: + dma_pio_timing |= 0x20; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_3: + dma_pio_timing |= 0x22; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_2: + dma_pio_timing |= 0x42; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_1: + dma_pio_timing |= 0x65; + pio_timing |= (0x03 << drive_number); + break; + case XFER_PIO_0: + default: + dma_pio_timing |= 0xA8; + pio_timing |= (0x03 << drive_number); + break; } - printk(":: UDMA 0x%02x PIO 0x%02x\n", drive_timing, pio_timing); + pci_write_config_byte(dev, drive_pci, ultra_timing); + pci_write_config_byte(dev, drive_pci2, dma_pio_timing); + pci_write_config_byte(dev, 0x4c, pio_timing); + +#ifdef DEBUG + printk(":: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n", + ultra_timing, dma_pio_timing, pio_timing); +#endif + if (speed > XFER_PIO_4) { + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); + } else { + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); + } err = ide_config_drive_speed(drive, speed); return (err); } @@ -109,12 +201,14 @@ static int config_chipset_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; + byte udma_66 = ((id->hw_config & 0x2000) && + (HWIF(drive)->udma_four)) ? 1 : 0; byte speed = 0x00; int rval; - if ((id->dma_ultra & 0x0010) && (HWIF(drive)->udma_four)) { + if ((id->dma_ultra & 0x0010) && (udma_66)) { speed = XFER_UDMA_4; - } else if ((id->dma_ultra & 0x0008) && (HWIF(drive)->udma_four)) { + } else if ((id->dma_ultra & 0x0008) && (udma_66)) { speed = XFER_UDMA_3; } else if (id->dma_ultra & 0x0004) { speed = XFER_UDMA_2; @@ -128,12 +222,6 @@ speed = XFER_MW_DMA_1; } else if (id->dma_mword & 0x0001) { speed = XFER_MW_DMA_0; - } else if (id->dma_1word & 0x0004) { - speed = XFER_SW_DMA_2; - } else if (id->dma_1word & 0x0002) { - speed = XFER_SW_DMA_1; - } else if (id->dma_1word & 0x0001) { - speed = XFER_SW_DMA_0; } else { return ((int) ide_dma_off_quietly); } @@ -143,7 +231,6 @@ rval = (int)( ((id->dma_ultra >> 11) & 3) ? ide_dma_on : ((id->dma_ultra >> 8) & 7) ? ide_dma_on : ((id->dma_mword >> 8) & 7) ? ide_dma_on : - ((id->dma_1word >> 8) & 7) ? ide_dma_on : ide_dma_off_quietly); return rval; @@ -222,8 +309,7 @@ } } else if (id->field_valid & 2) { try_dma_modes: - if ((id->dma_mword & 0x0007) || - (id->dma_1word & 0x0007)) { + if (id->dma_mword & 0x0007) { /* Force if Capable regular DMA modes */ dma_func = config_chipset_for_dma(drive); if (dma_func != ide_dma_on) @@ -265,16 +351,45 @@ return ide_dmaproc(func, drive); /* use standard DMA stuff */ } +unsigned int __init pci_init_amd7409 (struct pci_dev *dev, const char *name) +{ + unsigned long fixdma_base = dev->resource[4].start; + + if (!fixdma_base || fixdma_base == PCI_BASE_ADDRESS_IO_MASK) { + /* + * + */ + } else { + /* + * enable DMA capable bit, and "not" simplex only + */ + outb(inb(fixdma_base+2) & 0x60, fixdma_base+2); + + if (inb(fixdma_base+2) & 0x80) + printk("%s: simplex device: DMA will fail!!\n", name); + } +#if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) + amd7409_proc = 1; + bmide_dev = dev; + amd7409_display_info = &amd7409_get_info; +#endif /* DISPLAY_VIPER_TIMINGS && CONFIG_PROC_FS */ + + return 0; +} + unsigned int __init ata66_amd7409 (ide_hwif_t *hwif) { -#if 0 +#ifdef CONFIG_AMD7409_OVERRIDE + byte ata66 = 1; +#else byte ata66 = 0; +#endif /* CONFIG_AMD7409_OVERRIDE */ +#if 0 pci_read_config_byte(hwif->pci_dev, 0x48, &ata66); return ((ata66 & 0x02) ? 0 : 1); -#else - return 0; #endif + return ata66; } void __init ide_init_amd7409 (ide_hwif_t *hwif) @@ -287,4 +402,9 @@ hwif->drives[0].autotune = 1; hwif->drives[1].autotune = 1; } +} + +void ide_dmacapable_amd7409 (ide_hwif_t *hwif, unsigned long dmabase) +{ + ide_setup_dma(hwif, dmabase, 8); } diff -u --recursive --new-file v2.3.47/linux/drivers/block/buddha.c linux/drivers/block/buddha.c --- v2.3.47/linux/drivers/block/buddha.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/buddha.c Sat Feb 26 20:32:13 2000 @@ -42,7 +42,7 @@ #define BUDDHA_BASE2 0xa00 #define BUDDHA_BASE3 0xc00 -static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] = { +static const u_int __init buddha_bases[CATWEASEL_NUM_HWIFS] = { BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3 }; @@ -61,7 +61,7 @@ #define BUDDHA_STATUS 0x1e /* see status-bits */ #define BUDDHA_CONTROL 0x11a -static int buddha_offsets[IDE_NR_PORTS] = { +static int __init buddha_offsets[IDE_NR_PORTS] = { BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL, BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL }; @@ -75,7 +75,7 @@ #define BUDDHA_IRQ2 0xf40 /* interrupt */ #define BUDDHA_IRQ3 0xf80 -static const int buddha_irqports[CATWEASEL_NUM_HWIFS] = { +static const int __init buddha_irqports[CATWEASEL_NUM_HWIFS] = { BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3 }; @@ -109,7 +109,7 @@ * Any Buddha or Catweasel boards present? */ -static int find_buddha(void) +static int __init find_buddha(void) { struct zorro_dev *z = NULL; @@ -143,7 +143,7 @@ * We support only _one_ of them, no multiple boards! */ -void buddha_init(void) +void __init buddha_init(void) { hw_regs_t hw; int i, index; diff -u --recursive --new-file v2.3.47/linux/drivers/block/cmd640.c linux/drivers/block/cmd640.c --- v2.3.47/linux/drivers/block/cmd640.c Thu Nov 18 20:25:37 1999 +++ linux/drivers/block/cmd640.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996 + * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) */ @@ -290,7 +290,7 @@ return b; } -static int match_pci_cmd640_device (void) +static int __init match_pci_cmd640_device (void) { const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06}; unsigned int i; @@ -310,7 +310,7 @@ /* * Probe for CMD640x -- pci method 1 */ -static int probe_for_cmd640_pci1 (void) +static int __init probe_for_cmd640_pci1 (void) { get_cmd640_reg = get_cmd640_reg_pci1; put_cmd640_reg = put_cmd640_reg_pci1; @@ -324,7 +324,7 @@ /* * Probe for CMD640x -- pci method 2 */ -static int probe_for_cmd640_pci2 (void) +static int __init probe_for_cmd640_pci2 (void) { get_cmd640_reg = get_cmd640_reg_pci2; put_cmd640_reg = put_cmd640_reg_pci2; @@ -338,7 +338,7 @@ /* * Probe for CMD640x -- vlb */ -static int probe_for_cmd640_vlb (void) +static int __init probe_for_cmd640_vlb (void) { byte b; @@ -359,7 +359,7 @@ * Returns 1 if an IDE interface/drive exists at 0x170, * Returns 0 otherwise. */ -static int secondary_port_responding (void) +static int __init secondary_port_responding (void) { unsigned long flags; @@ -403,7 +403,7 @@ * Check whether prefetch is on for a drive, * and initialize the unmask flags for safe operation. */ -static void check_prefetch (unsigned int index) +static void __init check_prefetch (unsigned int index) { ide_drive_t *drive = cmd_drives[index]; byte b = get_cmd640_reg(prefetch_regs[index]); @@ -424,7 +424,7 @@ /* * Figure out which devices we control */ -static void setup_device_ptrs (void) +static void __init setup_device_ptrs (void) { unsigned int i; @@ -507,7 +507,7 @@ /* * This routine retrieves the initial drive timings from the chipset. */ -static void retrieve_drive_counts (unsigned int index) +static void __init retrieve_drive_counts (unsigned int index) { byte b; @@ -694,7 +694,7 @@ /* * Probe for a cmd640 chipset, and initialize it if found. Called from ide.c */ -int ide_probe_for_cmd640x (void) +int __init ide_probe_for_cmd640x (void) { #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED int second_port_toggled = 0; diff -u --recursive --new-file v2.3.47/linux/drivers/block/cmd64x.c linux/drivers/block/cmd64x.c --- v2.3.47/linux/drivers/block/cmd64x.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/block/cmd64x.c Sat Feb 26 20:32:13 2000 @@ -1,4 +1,4 @@ -/* $Id: cmd64x.c,v 1.20 1999/12/30 03:48:37 +/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16 * * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. * Note, this driver is not used at all on other systems because @@ -8,7 +8,7 @@ * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * Copyright (C) 1999 Andre Hedrick (andre@suse.com) + * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com) */ #include @@ -18,8 +18,10 @@ #include #include +#include "ide_modes.h" #define CMD_DEBUG 0 +#undef NO_WRITE #if CMD_DEBUG #define cmdprintk(x...) printk(##x) @@ -27,6 +29,235 @@ #define cmdprintk(x...) #endif +/* + * CMD64x specific registers definition. + */ + +#define CNTRL 0x51 +#define CNTRL_DIS_RA0 0x40 +#define CNTRL_DIS_RA1 0x80 +#define CNTRL_ENA_2ND 0x08 + +#define CMDTIM 0x52 +#define ARTTIM0 0x53 +#define DRWTIM0 0x54 +#define ARTTIM1 0x55 +#define DRWTIM1 0x56 +#define ARTTIM23 0x57 +#define ARTTIM23_DIS_RA2 0x04 +#define ARTTIM23_DIS_RA3 0x08 +#define DRWTIM23 0x58 +#define DRWTIM2 0x58 +#define BRST 0x59 +#define DRWTIM3 0x5b + +#define MRDMODE 0x71 + +#define DISPLAY_CMD64X_TIMINGS + +#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int cmd64x_get_info(char *, char **, off_t, int); +extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_CMD_648: + p += sprintf(p, "\n CMD648 Chipset.\n"); + break; + case PCI_DEVICE_ID_CMD_646: + p += sprintf(p, "\n CMD646 Chipset.\n"); + break; + case PCI_DEVICE_ID_CMD_643: + p += sprintf(p, "\n CMD643 Chipset.\n"); + break; + default: + p += sprintf(p, "\n CMD64? Chipse.\n"); + break; + } + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte cmd64x_proc = 0; + +/* + * Registers and masks for easy access by drive index: + */ +#if 0 +static byte prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23}; +static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3}; +#endif + +/* + * This routine writes the prepared setup/active/recovery counts + * for a drive into the cmd646 chipset registers to active them. + */ +static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count) +{ + unsigned long flags; + ide_drive_t *drives = HWIF(drive)->drives; + byte temp_b; + static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; + static const byte recovery_counts[] = + {15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0}; + static const byte arttim_regs[2][2] = { + { ARTTIM0, ARTTIM1 }, + { ARTTIM23, ARTTIM23 } + }; + static const byte drwtim_regs[2][2] = { + { DRWTIM0, DRWTIM1 }, + { DRWTIM2, DRWTIM3 } + }; + int channel = (int) HWIF(drive)->channel; + int slave = (drives != drive); /* Is this really the best way to determine this?? */ + + cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count, + active_count, recovery_count, drive->present); + /* + * Set up address setup count registers. + * Primary interface has individual count/timing registers for + * each drive. Secondary interface has one common set of registers, + * for address setup so we merge these timings, using the slowest + * value. + */ + if (channel) { + drive->drive_data = setup_count; + setup_count = IDE_MAX(drives[0].drive_data, drives[1].drive_data); + cmdprintk("Secondary interface, setup_count = %d\n", setup_count); + } + + /* + * Convert values to internal chipset representation + */ + setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count]; + active_count &= 0xf; /* Remember, max value is 16 */ + recovery_count = (int) recovery_counts[recovery_count]; + + cmdprintk("Final values = %d,%d,%d\n", setup_count, active_count, recovery_count); + + /* + * Now that everything is ready, program the new timings + */ + __save_flags (flags); + __cli(); + /* + * Program the address_setup clocks into ARTTIM reg, + * and then the active/recovery counts into the DRWTIM reg + */ + (void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b); +#ifndef NO_WRITE + (void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], + ((byte) setup_count) | (temp_b & 0x3f)); + (void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave], + (byte) ((active_count << 4) | recovery_count)); +#endif + cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]); + cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]); + __restore_flags(flags); +} + +/* + * Attempts to set the interface PIO mode. + * The preferred method of selecting PIO modes (e.g. mode 4) is + * "echo 'piomode:4' > /proc/ide/hdx/settings". Special cases are + * 8: prefetch off, 9: prefetch on, 255: auto-select best mode. + * Called with 255 at boot time. + */ +static void cmd64x_tuneproc (ide_drive_t *drive, byte mode_wanted) +{ + int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time; + byte recovery_count2, cycle_count; + int setup_count, active_count, recovery_count; + int bus_speed = ide_system_bus_speed(); + /*byte b;*/ + ide_pio_data_t d; + + switch (mode_wanted) { + case 8: /* set prefetch off */ + case 9: /* set prefetch on */ + mode_wanted &= 1; + /*set_prefetch_mode(index, mode_wanted);*/ + cmdprintk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis"); + return; + } + + (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d); + pio_mode = d.pio_mode; + cycle_time = d.cycle_time; + + /* + * I copied all this complicated stuff from cmd640.c and made a few minor changes. + * For now I am just going to pray that it is correct. + */ + if (pio_mode > 5) + pio_mode = 5; + setup_time = ide_pio_timings[pio_mode].setup_time; + active_time = ide_pio_timings[pio_mode].active_time; + recovery_time = cycle_time - (setup_time + active_time); + clock_time = 1000 / bus_speed; + cycle_count = (cycle_time + clock_time - 1) / clock_time; + + setup_count = (setup_time + clock_time - 1) / clock_time; + + active_count = (active_time + clock_time - 1) / clock_time; + + recovery_count = (recovery_time + clock_time - 1) / clock_time; + recovery_count2 = cycle_count - (setup_count + active_count); + if (recovery_count2 > recovery_count) + recovery_count = recovery_count2; + if (recovery_count > 16) { + active_count += recovery_count - 16; + recovery_count = 16; + } + if (active_count > 16) + active_count = 16; /* maximum allowed by cmd646 */ + + /* + * In a perfect world, we might set the drive pio mode here + * (using WIN_SETFEATURE) before continuing. + * + * But we do not, because: + * 1) this is the wrong place to do it (proper is do_special() in ide.c) + * 2) in practice this is rarely, if ever, necessary + */ + program_drive_counts (drive, setup_count, active_count, recovery_count); + + printk ("%s: selected cmd646 PIO mode%d (%dns)%s, clocks=%d/%d/%d\n", + drive->name, pio_mode, cycle_time, + d.overridden ? " (overriding vendor mode)" : "", + setup_count, active_count, recovery_count); +} + static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66) { struct hd_driveid *id = drive->id; @@ -123,7 +354,7 @@ static void config_chipset_for_pio (ide_drive_t *drive, unsigned int rev) { - /* FIXME!! figure out some PIOing junk.... */ + cmd64x_tuneproc(drive, 5); } static int cmd64x_config_drive_for_dma (ide_drive_t *drive) @@ -198,7 +429,7 @@ no_dma_set: config_chipset_for_pio(drive, class_rev); } - return hwif->dmaproc(dma_func, drive); + return HWIF(drive)->dmaproc(dma_func, drive); } static int cmd64x_dmaproc (ide_dma_action_t func, ide_drive_t *drive) @@ -277,9 +508,9 @@ #endif /* Setup interrupts. */ - (void) pci_read_config_byte(dev, 0x71, &mrdmode); + (void) pci_read_config_byte(dev, MRDMODE, &mrdmode); mrdmode &= ~(0x30); - (void) pci_write_config_byte(dev, 0x71, mrdmode); + (void) pci_write_config_byte(dev, MRDMODE, mrdmode); /* Use MEMORY READ LINE for reads. * NOTE: Although not mentioned in the PCI0646U specs, @@ -287,16 +518,26 @@ * back as set or not. The PCI0646U2 specs clarify * this point. */ - (void) pci_write_config_byte(dev, 0x71, mrdmode | 0x02); - + (void) pci_write_config_byte(dev, MRDMODE, mrdmode | 0x02); +#if 0 /* Set reasonable active/recovery/address-setup values. */ - (void) pci_write_config_byte(dev, 0x53, 0x40); - (void) pci_write_config_byte(dev, 0x54, 0x3f); - (void) pci_write_config_byte(dev, 0x55, 0x40); - (void) pci_write_config_byte(dev, 0x56, 0x3f); - (void) pci_write_config_byte(dev, 0x57, 0x5c); - (void) pci_write_config_byte(dev, 0x58, 0x3f); - (void) pci_write_config_byte(dev, 0x5b, 0x3f); + (void) pci_write_config_byte(dev, ARTTIM0, 0x40); + (void) pci_write_config_byte(dev, DRWTIM0, 0x3f); + (void) pci_write_config_byte(dev, ARTTIM1, 0x40); + (void) pci_write_config_byte(dev, DRWTIM1, 0x3f); + (void) pci_write_config_byte(dev, ARTTIM23, 0x5c); + (void) pci_write_config_byte(dev, DRWTIM23, 0x3f); + (void) pci_write_config_byte(dev, DRWTIM3, 0x3f); +#else + (void) pci_write_config_byte(dev, ARTTIM23, 0x1c); +#endif + +#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) + cmd64x_proc = 1; + bmide_dev = dev; + cmd64x_display_info = &cmd64x_get_info; +#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_PROC_FS */ + return 0; } @@ -317,8 +558,13 @@ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - if (!hwif->dma_base) + hwif->tuneproc = &cmd64x_tuneproc; + + if (!hwif->dma_base) { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; return; + } switch(dev->device) { case PCI_DEVICE_ID_CMD_643: diff -u --recursive --new-file v2.3.47/linux/drivers/block/cs5530.c linux/drivers/block/cs5530.c --- v2.3.47/linux/drivers/block/cs5530.c Sun Feb 13 19:29:03 2000 +++ linux/drivers/block/cs5530.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000 + * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000 * * Copyright (C) 2000 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -24,130 +24,63 @@ #include #include "ide_modes.h" -/* - * Return the mode name for a drive transfer mode value: - */ -static const char *strmode (byte mode) +#define DISPLAY_CS5530_TIMINGS + +#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int cs5530_get_info(char *, char **, off_t, int); +extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count) { - switch (mode) { - case XFER_UDMA_4: return("UDMA4"); - case XFER_UDMA_3: return("UDMA3"); - case XFER_UDMA_2: return("UDMA2"); - case XFER_UDMA_1: return("UDMA1"); - case XFER_UDMA_0: return("UDMA0"); - case XFER_MW_DMA_2: return("MDMA2"); - case XFER_MW_DMA_1: return("MDMA1"); - case XFER_MW_DMA_0: return("MDMA0"); - case XFER_SW_DMA_2: return("SDMA2"); - case XFER_SW_DMA_1: return("SDMA1"); - case XFER_SW_DMA_0: return("SDMA0"); - case XFER_PIO_4: return("PIO4"); - case XFER_PIO_3: return("PIO3"); - case XFER_PIO_2: return("PIO2"); - case XFER_PIO_1: return("PIO1"); - case XFER_PIO_0: return("PIO0"); - default: return("???"); - } + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n Cyrix 5530 Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; } +#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */ + +byte cs5530_proc = 0; + +extern char *ide_xfer_verbose (byte xfer_rate); /* * Set a new transfer mode at the drive */ int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode) { - int i, error = 1; - byte stat; - ide_hwif_t *hwif = HWIF(drive); + int error = 0; - printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, strmode(mode)); - /* - * If this is a DMA mode setting, then turn off all DMA bits. - * We will set one of them back on afterwards, if all goes well. - * - * Not sure why this is needed (it looks very silly), - * but other IDE chipset drivers also do this fiddling. ???? -ml - */ - switch (mode) { - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - drive->id->dma_ultra &= ~0xFF00; - drive->id->dma_mword &= ~0x0F00; - drive->id->dma_1word &= ~0x0F00; - } + printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode)); + error = ide_config_drive_speed(drive, mode); - /* - * Select the drive, and issue the SETFEATURES command - */ - disable_irq(hwif->irq); - udelay(1); - SELECT_DRIVE(HWIF(drive), drive); - udelay(1); - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); - OUT_BYTE(mode, IDE_NSECTOR_REG); - OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); - OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - udelay(1); /* spec allows drive 400ns to assert "BUSY" */ - - /* - * Wait for drive to become non-BUSY - */ - if ((stat = GET_STAT()) & BUSY_STAT) { - unsigned long flags, timeout; - __save_flags(flags); /* local CPU only */ - ide__sti(); /* local CPU only -- for jiffies */ - timeout = jiffies + WAIT_CMD; - while ((stat = GET_STAT()) & BUSY_STAT) { - if (0 < (signed long)(jiffies - timeout)) - break; - } - __restore_flags(flags); /* local CPU only */ - } - - /* - * Allow status to settle, then read it again. - * A few rare drives vastly violate the 400ns spec here, - * so we'll wait up to 10usec for a "good" status - * rather than expensively fail things immediately. - */ - for (i = 0; i < 10; i++) { - udelay(1); - if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) { - error = 0; - break; - } - } - enable_irq(hwif->irq); - - /* - * Turn dma bit on if all is okay - */ - if (error) { - (void) ide_dump_status(drive, "cs5530_set_xfer_mode", stat); - } else { - switch (mode) { - case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; - case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; - case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; - case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break; - case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break; - case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break; - case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break; - case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break; - case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break; - case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break; - case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break; - } - } return error; } @@ -302,8 +235,10 @@ case ide_dma_check: return cs5530_config_dma(drive); default: - return ide_dmaproc(func, drive); + break; } + /* Other cases are done by generic IDE-DMA code. */ + return ide_dmaproc(func, drive); } /* @@ -384,6 +319,13 @@ pci_write_config_byte(master_0, 0x43, 0xc1); restore_flags(flags); + +#if defined(DISPLAY_CS5530_TIMINGS) && defined(CONFIG_PROC_FS) + cs5530_proc = 1; + bmide_dev = dev; + cs5530_display_info = &cs5530_get_info; +#endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */ + return 0; } diff -u --recursive --new-file v2.3.47/linux/drivers/block/cy82c693.c linux/drivers/block/cy82c693.c --- v2.3.47/linux/drivers/block/cy82c693.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/cy82c693.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999 + * linux/drivers/block/cy82c693.c Version 0.34 Dec. 13, 1999 * * Copyright (C) 1998-99 Andreas S. Krebs (akrebs@altavista.net), Maintainer * Copyright (C) 1998-99 Andre Hedrick, Integrater @@ -54,7 +54,7 @@ #include "ide_modes.h" /* the current version */ -#define CY82_VERSION "CY82C693U driver v0.34 99-09-03 Andreas S. Krebs (akrebs@altavista.net)" +#define CY82_VERSION "CY82C693U driver v0.34 99-13-12 Andreas S. Krebs (akrebs@altavista.net)" /* * The following are used to debug the driver. @@ -439,4 +439,3 @@ hwif->drives[1].autotune = 1; } } - diff -u --recursive --new-file v2.3.47/linux/drivers/block/dtc2278.c linux/drivers/block/dtc2278.c --- v2.3.47/linux/drivers/block/dtc2278.c Thu May 13 11:04:54 1999 +++ linux/drivers/block/dtc2278.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996 + * linux/drivers/block/dtc2278.c Version 0.02 Feb 10, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ @@ -95,7 +95,7 @@ HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1; } -void init_dtc2278 (void) +void __init init_dtc2278 (void) { unsigned long flags; diff -u --recursive --new-file v2.3.47/linux/drivers/block/falconide.c linux/drivers/block/falconide.c --- v2.3.47/linux/drivers/block/falconide.c Thu May 13 11:04:54 1999 +++ linux/drivers/block/falconide.c Sat Feb 26 20:32:13 2000 @@ -40,7 +40,7 @@ #define ATA_HD_STATUS 0x1d /* see status-bits */ #define ATA_HD_CONTROL 0x39 -static int falconide_offsets[IDE_NR_PORTS] = { +static int __init falconide_offsets[IDE_NR_PORTS] = { ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL, ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1 }; @@ -50,7 +50,7 @@ * Probe for a Falcon IDE interface */ -void falconide_init(void) +void __init falconide_init(void) { if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) { hw_regs_t hw; diff -u --recursive --new-file v2.3.47/linux/drivers/block/gayle.c linux/drivers/block/gayle.c --- v2.3.47/linux/drivers/block/gayle.c Thu May 13 11:04:54 1999 +++ linux/drivers/block/gayle.c Sat Feb 26 20:32:13 2000 @@ -41,7 +41,7 @@ #define GAYLE_STATUS 0x1e /* see status-bits */ #define GAYLE_CONTROL 0x101a -static int gayle_offsets[IDE_NR_PORTS] = { +static int __init gayle_offsets[IDE_NR_PORTS] = { GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL, GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1 }; @@ -105,7 +105,7 @@ * Probe for a Gayle IDE interface (and optionally for an IDE doubler) */ -void gayle_init(void) +void __init gayle_init(void) { int a4000, i; diff -u --recursive --new-file v2.3.47/linux/drivers/block/hpt34x.c linux/drivers/block/hpt34x.c --- v2.3.47/linux/drivers/block/hpt34x.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/hpt34x.c Sat Feb 26 20:32:13 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/hpt34x.c Version 0.28 Dec. 13, 1999 + * linux/drivers/block/hpt34x.c Version 0.29 Feb. 10, 2000 * - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * @@ -16,6 +16,12 @@ * hdg: DMA 1 (0x0012 0x0052) (0x0030 0x0070) * hdh: DMA 1 (0x0052 0x0252) (0x0070 0x00f0) * + * ide-pci.c reference + * + * Since there are two cards that report almost identically, + * the only discernable difference is the values reported in pcicmd. + * Booting-BIOS card or HPT363 :: pcicmd == 0x07 + * Non-bootable card or HPT343 :: pcicmd == 0x05 */ #include @@ -27,7 +33,6 @@ #include #include #include - #include #include #include @@ -35,16 +40,56 @@ #include #include - #include "ide_modes.h" #ifndef SPLIT_BYTE #define SPLIT_BYTE(B,H,L) ((H)=(B>>4), (L)=(B-((B>>4)<<4))) #endif -#define HPT343_DEBUG_DRIVE_INFO 0 -#define HPT343_DISABLE_ALL_DMAING 0 -#define HPT343_DMA_DISK_ONLY 0 +#define HPT343_DEBUG_DRIVE_INFO 1 + +#define DISPLAY_HPT34X_TIMINGS +#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int hpt34x_get_info(char *, char **, off_t, int); +extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n HPT34X Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte hpt34x_proc = 0; extern char *ide_xfer_verbose (byte xfer_rate); @@ -109,12 +154,8 @@ struct hd_driveid *id = drive->id; byte speed = 0x00; -#if HPT343_DISABLE_ALL_DMAING - return ((int) ide_dma_off); -#elif HPT343_DMA_DISK_ONLY if (drive->media != ide_disk) return ((int) ide_dma_off_quietly); -#endif /* HPT343_DISABLE_ALL_DMAING */ hpt34x_clear_chipset(drive); @@ -249,14 +290,13 @@ fast_ata_pio: dma_func = ide_dma_off_quietly; no_dma_set: - config_chipset_for_pio(drive); } -#if 0 +#ifndef CONFIG_HPT34X_AUTODMA if (dma_func == ide_dma_on) dma_func = ide_dma_off; -#endif +#endif /* CONFIG_HPT34X_AUTODMA */ return HWIF(drive)->dmaproc(dma_func, drive); } @@ -273,18 +313,10 @@ { ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; - byte unit = (drive->select.b.unit & 0x01); unsigned int count, reading = 0; byte dma_stat; switch (func) { - case ide_dma_off: - case ide_dma_off_quietly: - outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); - break; - case ide_dma_on: - outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); - break; case ide_dma_check: return config_drive_xfer_rate(drive); case ide_dma_read: @@ -357,11 +389,16 @@ pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start); pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start); pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start); - pci_write_config_word(dev, PCI_COMMAND, cmd); __restore_flags(flags); /* local CPU only */ +#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) + hpt34x_proc = 1; + bmide_dev = dev; + hpt34x_display_info = &hpt34x_get_info; +#endif /* DISPLAY_HPT34X_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } @@ -372,11 +409,7 @@ unsigned short pcicmd = 0; pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd); -#ifdef CONFIG_BLK_DEV_HPT34X_DMA -#if 0 hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; -#endif -#endif /* CONFIG_BLK_DEV_HPT34X_DMA */ hwif->dmaproc = &hpt34x_dmaproc; } else { hwif->drives[0].autotune = 1; diff -u --recursive --new-file v2.3.47/linux/drivers/block/hpt366.c linux/drivers/block/hpt366.c --- v2.3.47/linux/drivers/block/hpt366.c Thu Feb 10 17:11:06 2000 +++ linux/drivers/block/hpt366.c Sat Feb 26 20:32:13 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/hpt366.c Version 0.15 Dec. 22, 1999 + * linux/drivers/block/hpt366.c Version 0.16 Feb. 10, 2000 * - * Copyright (C) 1999 Andre Hedrick + * Copyright (C) 1999-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License * * Thanks to HighPoint Technologies for their assistance, and hardware. @@ -30,6 +30,13 @@ #include "ide_modes.h" +#define DISPLAY_HPT366_TIMINGS + +#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include +#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ + const char *bad_ata66_4[] = { "WDC AC310200R", NULL @@ -120,6 +127,48 @@ #define HPT366_ALLOW_ATA66_4 1 #define HPT366_ALLOW_ATA66_3 1 +#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) +static int hpt366_get_info(char *, char **, off_t, int); +extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; +static struct pci_dev *bmide2_dev; + +static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = bmide_dev->resource[4].start; + u32 bibma2 = bmide2_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + if (bmide2_dev) + c1 = inb_p((unsigned short)bibma2 + 0x02); + + p += sprintf(p, "\n HPT366 Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer;/* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte hpt366_proc = 0; + extern char *ide_xfer_verbose (byte xfer_rate); byte hpt363_shared_irq = 0; byte hpt363_shared_pin = 0; @@ -263,20 +312,20 @@ pci_read_config_byte(HWIF(drive)->pci_dev, 0x51, ®51h); -#ifdef CONFIG_HPT366_FAST_IRQ_PREDICTION +#ifdef CONFIG_HPT366_FIP /* * Some drives prefer/allow for the method of handling interrupts. */ if (!(reg51h & 0x80)) pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h|0x80); -#else /* ! CONFIG_HPT366_FAST_IRQ_PREDICTION */ +#else /* ! CONFIG_HPT366_FIP */ /* * Disable the "fast interrupt" prediction. * Instead, always wait for the real interrupt from the drive! */ if (reg51h & 0x80) pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, reg51h & ~0x80); -#endif /* CONFIG_HPT366_FAST_IRQ_PREDICTION */ +#endif /* CONFIG_HPT366_FIP */ /* * Preserve existing PIO settings: @@ -420,7 +469,6 @@ * This is specific to the HPT366 UDMA bios chipset * by HighPoint|Triones Technologies, Inc. */ - int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive) { byte reg50h = 0; @@ -434,7 +482,6 @@ pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, ®50h); /* ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); */ case ide_dma_timeout: - break; default: break; } @@ -464,6 +511,17 @@ if (test != 0x08) pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); +#if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) + if (!hpt366_proc) { + hpt366_proc = 1; + bmide_dev = dev; + hpt366_display_info = &hpt366_get_info; + } + if ((hpt366_proc) && ((dev->devfn - bmide_dev->devfn) == 1)) { + bmide2_dev = dev; + } +#endif /* DISPLAY_HPT366_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } @@ -482,18 +540,6 @@ void __init ide_init_hpt366 (ide_hwif_t *hwif) { -#if 0 - if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_irq)) { - hwif->mate = &ide_hwifs[hwif->index-1]; - hwif->mate->mate = hwif; - hwif->serialized = hwif->mate->serialized = 1; - } - - if ((PCI_FUNC(hwif->pci_dev->devfn) & 1) && (hpt363_shared_pin)) { - - } -#endif - hwif->tuneproc = &hpt366_tune_drive; if (hwif->dma_base) { hwif->dmaproc = &hpt366_dmaproc; diff -u --recursive --new-file v2.3.47/linux/drivers/block/ht6560b.c linux/drivers/block/ht6560b.c --- v2.3.47/linux/drivers/block/ht6560b.c Thu May 13 11:04:54 1999 +++ linux/drivers/block/ht6560b.c Sat Feb 26 20:32:13 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ht6580.c Version 0.04 Mar 19, 1996 + * linux/drivers/block/ht6560b.c Version 0.07 Feb 1, 2000 * - * Copyright (C) 1995-1996 Linus Torvalds & author (see below) + * Copyright (C) 1995-2000 Linus Torvalds & author (see below) */ /* @@ -12,42 +12,31 @@ * * Version 0.03 Some cleanups * - * I reviewed some assembler source listings of htide drivers and found - * out how they setup those cycle time interfacing values, as they at Holtek - * call them. IDESETUP.COM that is supplied with the drivers figures out - * optimal values and fetches those values to drivers. I found out that - * they use IDE_SELECT_REG to fetch timings to the ide board right after - * interface switching. After that it was quite easy to add code to - * ht6560b.c. + * Version 0.05 PIO mode cycle timings auto-tune using bus-speed * - * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine - * for hda and hdc. But hdb needed higher values to work, so I guess - * that sometimes it is necessary to give higher value than IDESETUP - * gives. [see cmd640.c for an extreme example of this. -ml] + * Version 0.06 Prefetch mode now defaults no OFF. To set + * prefetch mode OFF/ON use "hdparm -p8/-p9". + * Unmask irq is disabled when prefetch mode + * is enabled. * - * Perhaps I should explain something about these timing values: - * The higher nibble of value is the Recovery Time (rt) and the lower nibble - * of the value is the Active Time (at). Minimum value 2 is the fastest and - * the maximum value 15 is the slowest. Default values should be 15 for both. - * So 0x24 means 2 for rt and 4 for at. Each of the drives should have - * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or - * similar. If value is too small there will be all sorts of failures. - * - * Port 0x3e6 bit 0x20 sets these timings on/off. If 0x20 bit is set - * these timings are disabled. + * Version 0.07 Trying to fix CD-ROM detection problem. + * "Prefetch" mode bit OFF for ide disks and + * ON for anything else. * - * Mikko Ala-Fossi * - * More notes: + * HT-6560B EIDE-controller support + * To activate controller support use kernel parameter "ide0=ht6560b". + * Use hdparm utility to enable PIO mode support. * - * There's something still missing from the initialization code, though. - * If I have booted to dos sometime after power on, I can get smaller - * timing values working. Perhaps I could soft-ice the initialization. + * Author: Mikko Ala-Fossi + * Jan Evert van Grootheest * - * -=- malafoss@snakemail.hut.fi -=- searching the marvels of universe -=- + * Try: http://www.maf.iki.fi/~maf/ht6560b/ */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ +#define HT6560B_VERSION "v0.07" + +#undef REALLY_SLOW_IO /* most systems can safely undef this */ #include #include @@ -63,175 +52,291 @@ #include "ide_modes.h" -/* - * This routine handles interface switching for the peculiar hardware design - * on the F.G.I./Holtek HT-6560B VLB IDE interface. - * The HT-6560B can only enable one IDE port at a time, and requires a - * silly sequence (below) whenever we switch between primary and secondary. - * - * This stuff is courtesy of malafoss@snakemail.hut.fi - * (or maf@nemesis.tky.hut.fi) - * - * At least one user has reported that this code can confuse the floppy - * controller and/or driver -- perhaps this should be changed to use - * a read-modify-write sequence, so as not to disturb other bits in the reg? - */ +/* #define DEBUG */ /* remove comments for DEBUG messages */ /* - * The special i/o-port that HT-6560B uses to select interfaces: + * The special i/o-port that HT-6560B uses to configuration: + * bit0 (0x01): "1" selects secondary interface + * bit2 (0x04): "1" enables FIFO function + * bit5 (0x20): "1" enables prefetched data read function (???) + * + * The special i/o-port that HT-6560A uses to configuration: + * bit0 (0x01): "1" selects secondary interface + * bit1 (0x02): "1" enables prefetched data read function + * bit2 (0x04): "0" enables multi-master system (?) + * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?) */ -#define HT_SELECT_PORT 0x3e6 - +#define HT_CONFIG_PORT 0x3e6 +#define HT_CONFIG(drivea) (byte)(((drivea)->drive_data & 0xff00) >> 8) /* - * We don't know what all of the bits are for, but we *do* know about these: - * bit5 (0x20): "1" selects slower speed by disabling use of timing values - * bit0 (0x01): "1" selects second interface + * FIFO + PREFETCH (both a/b-model) */ -static byte ht6560b_selects [2][MAX_DRIVES] = {{0x3c,0x3c}, {0x3d,0x3d}}; +#define HT_CONFIG_DEFAULT 0x1c /* no prefetch */ +/* #define HT_CONFIG_DEFAULT 0x3c */ /* with prefetch */ +#define HT_SECONDARY_IF 0x01 +#define HT_PREFETCH_MODE 0x20 /* - * VLB ht6560b Timing values: + * ht6560b Timing values: + * + * I reviewed some assembler source listings of htide drivers and found + * out how they setup those cycle time interfacing values, as they at Holtek + * call them. IDESETUP.COM that is supplied with the drivers figures out + * optimal values and fetches those values to drivers. I found out that + * they use IDE_SELECT_REG to fetch timings to the ide board right after + * interface switching. After that it was quite easy to add code to + * ht6560b.c. + * + * IDESETUP.COM gave me values 0x24, 0x45, 0xaa, 0xff that worked fine + * for hda and hdc. But hdb needed higher values to work, so I guess + * that sometimes it is necessary to give higher value than IDESETUP + * gives. [see cmd640.c for an extreme example of this. -ml] + * + * Perhaps I should explain something about these timing values: + * The higher nibble of value is the Recovery Time (rt) and the lower nibble + * of the value is the Active Time (at). Minimum value 2 is the fastest and + * the maximum value 15 is the slowest. Default values should be 15 for both. + * So 0x24 means 2 for rt and 4 for at. Each of the drives should have + * both values, and IDESETUP gives automatically rt=15 st=15 for CDROMs or + * similar. If value is too small there will be all sorts of failures. * * Timing byte consists of - * High nibble: Recovery Time (rt) - * The valid values range from 2 to 15. The default is 15. + * High nibble: Recovery Cycle Time (rt) + * The valid values range from 2 to 15. The default is 15. * - * Low nibble: Active Time (at) - * The valid values range from 2 to 15. The default is 15. + * Low nibble: Active Cycle Time (at) + * The valid values range from 2 to 15. The default is 15. * * You can obtain optimized timing values by running Holtek IDESETUP.COM * for DOS. DOS drivers get their timing values from command line, where * the first value is the Recovery Time and the second value is the * Active Time for each drive. Smaller value gives higher speed. * In case of failures you should probably fall back to a higher value. - * - * Here's an example to make it clearer: - * - * DOS: DEVICE=C:\bin\HTIDE\HTIDE.SYS /D0=2,4 /D1=4,5 /D2=10,10 /D3=15,15 - * Linux: byte ht6560b_timings [][] = {{0x24, 0x45}, {0xaa, 0xff}}; - * - * Note: There are no ioctls to change these values directly, - * but settings can be approximated as PIO modes, using "hdparm": - * - * rc.local: hdparm -p3 /dev/hda -p2 /dev/hdb -p1 /dev/hdc -p0 /dev/hdd */ +#define HT_TIMING(drivea) (byte)((drivea)->drive_data & 0x00ff) +#define HT_TIMING_DEFAULT 0xff -static byte ht6560b_timings [2][MAX_DRIVES] = {{0xff,0xff}, {0xff,0xff}}; - -static byte pio_to_timings[6] = {0xff, 0xaa, 0x45, 0x24, 0x13, 0x12}; +/* + * This routine handles interface switching for the peculiar hardware design + * on the F.G.I./Holtek HT-6560B VLB IDE interface. + * The HT-6560B can only enable one IDE port at a time, and requires a + * silly sequence (below) whenever we switch between primary and secondary. + */ /* * This routine is invoked from ide.c to prepare for access to a given drive. */ static void ht6560b_selectproc (ide_drive_t *drive) { - byte t; unsigned long flags; static byte current_select = 0; static byte current_timing = 0; - byte select = ht6560b_selects[HWIF(drive)->index][drive->select.b.unit]; - byte timing = ht6560b_timings[HWIF(drive)->index][drive->select.b.unit]; - + byte select, timing; + + __save_flags (flags); /* local CPU only */ + __cli(); /* local CPU only */ + + select = HT_CONFIG(drive); + timing = HT_TIMING(drive); + if (select != current_select || timing != current_timing) { current_select = select; current_timing = timing; - __save_flags (flags); /* local CPU only */ - __cli(); /* local CPU only */ - (void) inb(HT_SELECT_PORT); - (void) inb(HT_SELECT_PORT); - (void) inb(HT_SELECT_PORT); + if (drive->media != ide_disk || !drive->present) + select |= HT_PREFETCH_MODE; + (void) inb(HT_CONFIG_PORT); + (void) inb(HT_CONFIG_PORT); + (void) inb(HT_CONFIG_PORT); + (void) inb(HT_CONFIG_PORT); + outb(select, HT_CONFIG_PORT); /* - * Note: input bits are reversed to output bits!! + * Set timing for this drive: */ - t = inb(HT_SELECT_PORT) ^ 0x3f; - t &= (~0x21); - t |= (current_select & 0x21); - outb(t, HT_SELECT_PORT); - /* - * Set timing for this drive: - */ - outb (timing, IDE_SELECT_REG); - (void) inb (IDE_STATUS_REG); - __restore_flags (flags); /* local CPU only */ + outb(timing, IDE_SELECT_REG); + (void) inb(IDE_STATUS_REG); #ifdef DEBUG - printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing); + printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing); #endif } + __restore_flags (flags); /* local CPU only */ } /* * Autodetection and initialization of ht6560b */ -int try_to_init_ht6560b(void) +static int __init try_to_init_ht6560b(void) { byte orig_value; int i; - + /* Autodetect ht6560b */ - if ((orig_value=inb(HT_SELECT_PORT)) == 0xff) + if ((orig_value=inb(HT_CONFIG_PORT)) == 0xff) return 0; - + for (i=3;i>0;i--) { - outb(0x00, HT_SELECT_PORT); - if (!( (~inb(HT_SELECT_PORT)) & 0x3f )) { - outb(orig_value, HT_SELECT_PORT); - return 0; + outb(0x00, HT_CONFIG_PORT); + if (!( (~inb(HT_CONFIG_PORT)) & 0x3f )) { + outb(orig_value, HT_CONFIG_PORT); + return 0; } } - outb(0x00, HT_SELECT_PORT); - if ((~inb(HT_SELECT_PORT))& 0x3f) { - outb(orig_value, HT_SELECT_PORT); + outb(0x00, HT_CONFIG_PORT); + if ((~inb(HT_CONFIG_PORT))& 0x3f) { + outb(orig_value, HT_CONFIG_PORT); return 0; } /* - * Ht6560b autodetected: - * reverse input bits to output bits - * initialize bit1 to 0 + * Ht6560b autodetected */ - outb((orig_value ^ 0x3f) & 0xfd, HT_SELECT_PORT); - - printk("\nht6560b: detected and initialized"); + outb(HT_CONFIG_DEFAULT, HT_CONFIG_PORT); + outb(HT_TIMING_DEFAULT, 0x1f6); /* IDE_SELECT_REG */ + (void) inb(0x1f7); /* IDE_STATUS_REG */ + + printk("\nht6560b " HT6560B_VERSION + ": chipset detected and initialized" +#ifdef DEBUG + " with debug enabled" +#endif + ); return 1; } -static void tune_ht6560b (ide_drive_t *drive, byte pio) +static byte ht_pio2timings(ide_drive_t *drive, byte pio) { - unsigned int hwif, unit; + int bus_speed, active_time, recovery_time; + int active_cycles, recovery_cycles; + ide_pio_data_t d; + + if (pio) { + pio = ide_get_best_pio_mode(drive, pio, 5, &d); + + /* + * Just like opti621.c we try to calculate the + * actual cycle time for recovery and activity + * according system bus speed. + */ + bus_speed = ide_system_bus_speed(); + active_time = ide_pio_timings[pio].active_time; + recovery_time = d.cycle_time + - active_time + - ide_pio_timings[pio].setup_time; + /* + * Cycle times should be Vesa bus cycles + */ + active_cycles = (active_time * bus_speed + 999) / 1000; + recovery_cycles = (recovery_time * bus_speed + 999) / 1000; + /* + * Upper and lower limits + */ + if (active_cycles < 2) active_cycles = 2; + if (recovery_cycles < 2) recovery_cycles = 2; + if (active_cycles > 15) active_cycles = 15; + if (recovery_cycles > 15) recovery_cycles = 0; /* 0==16 */ + +#ifdef DEBUG + printk("ht6560b: drive %s setting pio=%d recovery=%d (%dns) active=%d (%dns)\n", drive->name, pio, recovery_cycles, recovery_time, active_cycles, active_time); +#endif + + return (byte)((recovery_cycles << 4) | active_cycles); + } else { + +#ifdef DEBUG + printk("ht6560b: drive %s setting pio=0\n", drive->name); +#endif + + return HT_TIMING_DEFAULT; /* default setting */ + } +} + +/* + * Enable/Disable so called prefetch mode + */ +static void ht_set_prefetch(ide_drive_t *drive, byte state) +{ + unsigned long flags; + int t = HT_PREFETCH_MODE << 8; + + save_flags (flags); /* all CPUs */ + cli(); /* all CPUs */ + + /* + * Prefetch mode and unmask irq seems to conflict + */ + if (state) { + drive->drive_data |= t; /* enable prefetch mode */ + drive->no_unmask = 1; + drive->unmask = 0; + } else { + drive->drive_data &= ~t; /* disable prefetch mode */ + drive->no_unmask = 0; + } + + restore_flags (flags); /* all CPUs */ + +#ifdef DEBUG + printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis")); +#endif +} - if (pio == 255) { /* auto-tune */ - if (drive->media != ide_disk) - pio = 0; /* some CDROMs don't like fast modes (?) */ - else - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); - } - unit = drive->select.b.unit; - hwif = HWIF(drive)->index; - ht6560b_timings[hwif][unit] = pio_to_timings[pio]; - if (pio == 0) - ht6560b_selects[hwif][unit] |= 0x20; - else - ht6560b_selects[hwif][unit] &= ~0x20; +static void tune_ht6560b (ide_drive_t *drive, byte pio) +{ + unsigned long flags; + byte timing; + + switch (pio) { + case 8: /* set prefetch off */ + case 9: /* set prefetch on */ + ht_set_prefetch(drive, pio & 1); + return; + } + + timing = ht_pio2timings(drive, pio); + + save_flags (flags); /* all CPUs */ + cli(); /* all CPUs */ + + drive->drive_data &= 0xff00; + drive->drive_data |= timing; + + restore_flags (flags); /* all CPUs */ + +#ifdef DEBUG + printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing); +#endif } -void init_ht6560b (void) +void __init init_ht6560b (void) { - if (check_region(HT_SELECT_PORT,1)) { - printk("\nht6560b: PORT 0x3e6 ALREADY IN USE\n"); + int t; + + if (check_region(HT_CONFIG_PORT,1)) { + printk(KERN_ERR "ht6560b: PORT %#x ALREADY IN USE\n", HT_CONFIG_PORT); } else { if (try_to_init_ht6560b()) { - request_region(HT_SELECT_PORT, 1, ide_hwifs[0].name); + request_region(HT_CONFIG_PORT, 1, ide_hwifs[0].name); ide_hwifs[0].chipset = ide_ht6560b; ide_hwifs[1].chipset = ide_ht6560b; ide_hwifs[0].selectproc = &ht6560b_selectproc; ide_hwifs[1].selectproc = &ht6560b_selectproc; ide_hwifs[0].tuneproc = &tune_ht6560b; ide_hwifs[1].tuneproc = &tune_ht6560b; - ide_hwifs[0].serialized = 1; - ide_hwifs[1].serialized = 1; + ide_hwifs[0].serialized = 1; /* is this needed? */ + ide_hwifs[1].serialized = 1; /* is this needed? */ ide_hwifs[0].mate = &ide_hwifs[1]; ide_hwifs[1].mate = &ide_hwifs[0]; ide_hwifs[1].channel = 1; + + /* + * Setting default configurations for drives + */ + t = (HT_CONFIG_DEFAULT << 8); + t |= HT_TIMING_DEFAULT; + ide_hwifs[0].drives[0].drive_data = t; + ide_hwifs[0].drives[1].drive_data = t; + t |= (HT_SECONDARY_IF << 8); + ide_hwifs[1].drives[0].drive_data = t; + ide_hwifs[1].drives[1].drive_data = t; } else - printk("\nht6560b: not found\n"); + printk(KERN_ERR "ht6560b: not found\n"); } } diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h --- v2.3.47/linux/drivers/block/ide-cd.h Tue Dec 14 01:27:23 1999 +++ linux/drivers/block/ide-cd.h Sat Feb 26 20:51:25 2000 @@ -1,11 +1,11 @@ -#ifndef _IDE_CD_H -#define _IDE_CD_H /* * linux/drivers/block/ide_cd.h * - * Copyright (C) 1996, 1997, 1998 Erik Andersen - * Copyright (C) 1998, 1999 Jens Axboe + * Copyright (C) 1996-98 Erik Andersen + * Copyright (C) 1998-2000 Jens Axboe */ +#ifndef _IDE_CD_H +#define _IDE_CD_H #include #include diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.3.47/linux/drivers/block/ide-disk.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/ide-disk.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999 + * linux/drivers/block/ide-disk.c Version 1.09 April 23, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.3.47/linux/drivers/block/ide-dma.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/block/ide-dma.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 + * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 * * Copyright (c) 1999 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -91,6 +91,8 @@ #include #include +extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); + #ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS struct drive_list_entry { @@ -401,6 +403,7 @@ { ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; + byte unit = (drive->select.b.unit & 0x01); unsigned int count, reading = 0; byte dma_stat; @@ -408,8 +411,11 @@ case ide_dma_off: printk("%s: DMA disabled\n", drive->name); case ide_dma_off_quietly: + outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2); case ide_dma_on: drive->using_dma = (func == ide_dma_on); + if (drive->using_dma) + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); return 0; case ide_dma_check: return config_drive_for_dma (drive); @@ -424,7 +430,7 @@ drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; - ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);/* issue cmd to drive */ + ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); case ide_dma_begin: /* Note that this is done *after* the cmd has @@ -449,12 +455,10 @@ return check_drive_lists(drive, (func == ide_dma_good_drive)); case ide_dma_lostirq: case ide_dma_timeout: - /* - * printk("ide_dmaproc: chipset supported func only: %d\n", func); - */ + printk("ide_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func); return 1; default: - printk("ide_dmaproc: unsupported func: %d\n", func); + printk("ide_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func); return 1; } } @@ -541,14 +545,15 @@ } } if (dma_base) { - if (extra) /* PDC20246, PDC20262, & HPT343 */ + if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */ request_region(dma_base+16, extra, name); dma_base += hwif->channel ? 8 : 0; hwif->dma_extra = extra; switch(dev->device) { - case PCI_DEVICE_ID_CMD_643: case PCI_DEVICE_ID_AL_M5219: + case PCI_DEVICE_ID_AMD_VIPER_7409: + case PCI_DEVICE_ID_CMD_643: outb(inb(dma_base+2) & 0x60, dma_base+2); if (inb(dma_base+2) & 0x80) { printk("%s: simplex device: DMA forced\n", name); diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide-features.c linux/drivers/block/ide-features.c --- v2.3.47/linux/drivers/block/ide-features.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/ide-features.c Sat Feb 26 20:32:13 2000 @@ -1,16 +1,15 @@ /* - * linux/drivers/block/ide-features.c + * linux/drivers/block/ide-features.c Version 0.03 Feb. 10, 2000 * - * Copyright (C) 1999 Linus Torvalds & authors (see below) + * Copyright (C) 1999-2000 Linus Torvalds & authors (see below) * - * Andre Hedrick + * Copyright (C) 1999-2000 Andre Hedrick * * Extracts if ide.c to address the evolving transfer rate code for - * the SETFEATURES_XFER callouts. Below are original authors of some or - * various parts of any given function below. + * the SETFEATURES_XFER callouts. Various parts of any given function + * are credited to previous ATA-IDE maintainers. * - * Mark Lord - * Gadi Oxman + * May be copied or modified under the terms of the GNU General Public License */ #define __NO_VERSION__ @@ -36,12 +35,15 @@ #include #include +#define SETFEATURES_CONTROL_REG (0) /* some arch's may need */ + /* - * + * A Verbose noise maker for debugging on the attempted transfer rates. */ char *ide_xfer_verbose (byte xfer_rate) { switch(xfer_rate) { + case XFER_UDMA_7: return("UDMA 7"); case XFER_UDMA_6: return("UDMA 6"); case XFER_UDMA_5: return("UDMA 5"); case XFER_UDMA_4: return("UDMA 4"); @@ -71,14 +73,42 @@ char *ide_media_verbose (ide_drive_t *drive) { switch (drive->media) { - case ide_disk: return("disk "); - case ide_cdrom: return("cdrom "); - case ide_tape: return("tape "); - case ide_floppy: return("floppy"); - default: return("??????"); + case ide_scsi: return("scsi "); + case ide_disk: return("disk "); + case ide_optical: return("optical"); + case ide_cdrom: return("cdrom "); + case ide_tape: return("tape "); + case ide_floppy: return("floppy "); + default: return("???????"); } } +/* + * A Verbose noise maker for debugging on the attempted dmaing calls. + */ +char *ide_dmafunc_verbose (ide_dma_action_t dmafunc) +{ + switch (dmafunc) { + case ide_dma_read: return("ide_dma_read"); + case ide_dma_write: return("ide_dma_write"); + case ide_dma_begin: return("ide_dma_begin"); + case ide_dma_end: return("ide_dma_end:"); + case ide_dma_check: return("ide_dma_check"); + case ide_dma_on: return("ide_dma_on"); + case ide_dma_off: return("ide_dma_off"); + case ide_dma_off_quietly: return("ide_dma_off_quietly"); + case ide_dma_test_irq: return("ide_dma_test_irq"); + case ide_dma_bad_drive: return("ide_dma_bad_drive"); + case ide_dma_good_drive: return("ide_dma_good_drive"); + case ide_dma_lostirq: return("ide_dma_lostirq"); + case ide_dma_timeout: return("ide_dma_timeout"); + default: return("unknown"); + } +} + +/* + * Update the + */ int ide_driveid_update (ide_drive_t *drive) { /* @@ -129,50 +159,6 @@ } /* - * Similar to ide_wait_stat(), except it never calls ide_error internally. - * This is a kludge to handle the new ide_config_drive_speed() function, - * and should not otherwise be used anywhere. Eventually, the tuneproc's - * should be updated to return ide_startstop_t, in which case we can get - * rid of this abomination again. :) -ml - */ -int ide_wait_noerr (ide_drive_t *drive, byte good, byte bad, unsigned long timeout) -{ - byte stat; - int i; - unsigned long flags; - - udelay(1); /* spec allows drive 400ns to assert "BUSY" */ - if ((stat = GET_STAT()) & BUSY_STAT) { - __save_flags(flags); /* local CPU only */ - ide__sti(); /* local CPU only */ - timeout += jiffies; - while ((stat = GET_STAT()) & BUSY_STAT) { - if (0 < (signed long)(jiffies - timeout)) { - __restore_flags(flags); /* local CPU only */ - (void)ide_dump_status(drive, "ide_wait_noerr", stat); - return 1; - } - } - __restore_flags(flags); /* local CPU only */ - } - /* - * Allow status to settle, then read it again. - * A few rare drives vastly violate the 400ns spec here, - * so we'll wait up to 10usec for a "good" status - * rather than expensively fail things immediately. - * This fix courtesy of Matthew Faupel & Niccolo Rigacci. - */ - for (i = 0; i < 10; i++) { - udelay(1); - if (OK_STAT((stat = GET_STAT()), good, bad)) - return 0; - } - (void)ide_dump_status(drive, "ide_wait_noerr", stat); - return 1; -} - - -/* * Verify that we are doing an approved SETFEATURES_XFER with respect * to the hardware being able to support request. Since some hardware * can improperly report capabilties, we check to see if the host adapter @@ -213,70 +199,96 @@ return 0; } -#if 0 -ide_startstop_t set_drive_speed_intr (ide_drive_t *drive) -{ - byte stat; - - if (!OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT)) /* - * if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,BAD_STAT)) - * if (stat != DRIVE_READY) + * Similar to ide_wait_stat(), except it never calls ide_error internally. + * This is a kludge to handle the new ide_config_drive_speed() function, + * and should not otherwise be used anywhere. Eventually, the tuneproc's + * should be updated to return ide_startstop_t, in which case we can get + * rid of this abomination again. :) -ml + * + * It is gone.......... + * + * const char *msg == consider adding for verbose errors. */ - (void) ide_dump_status(drive, "set_drive_speed_status", stat); - - return ide_stopped; -} -#endif - int ide_config_drive_speed (ide_drive_t *drive, byte speed) { - unsigned long flags; - int err; + ide_hwif_t *hwif = HWIF(drive); + int i, error = 1; + byte unit = (drive->select.b.unit & 0x01); byte stat; - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ - /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, * but for some reason these don't work at * this point (lost interrupt). */ + /* + * Select the drive, and issue the SETFEATURES command + */ + disable_irq(hwif->irq); /* disable_irq_nosync ?? */ + udelay(1); SELECT_DRIVE(HWIF(drive), drive); + udelay(1); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); OUT_BYTE(speed, IDE_NSECTOR_REG); OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); - - err = ide_wait_noerr(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD); - -#if 0 - if (IDE_CONTROL_REG) + if ((IDE_CONTROL_REG) && (SETFEATURES_CONTROL_REG)) OUT_BYTE(drive->ctl, IDE_CONTROL_REG); -#endif + udelay(1); + /* + * Wait for drive to become non-BUSY + */ + if ((stat = GET_STAT()) & BUSY_STAT) { + unsigned long flags, timeout; + __save_flags(flags); /* local CPU only */ + ide__sti(); /* local CPU only -- for jiffies */ + timeout = jiffies + WAIT_CMD; + while ((stat = GET_STAT()) & BUSY_STAT) { + if (0 < (signed long)(jiffies - timeout)) + break; + } + __restore_flags(flags); /* local CPU only */ + } - __restore_flags(flags); /* local CPU only */ + /* + * Allow status to settle, then read it again. + * A few rare drives vastly violate the 400ns spec here, + * so we'll wait up to 10usec for a "good" status + * rather than expensively fail things immediately. + * This fix courtesy of Matthew Faupel & Niccolo Rigacci. + */ + for (i = 0; i < 10; i++) { + udelay(1); + if (OK_STAT((stat = GET_STAT()), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) { + error = 0; + break; + } + } -#if 0 - ide_set_handler(drive, &set_drive_speed_intr, WAIT_CMD, NULL); -#endif + enable_irq(hwif->irq); - stat = GET_STAT(); - if (stat != DRIVE_READY) + if (error) { (void) ide_dump_status(drive, "set_drive_speed_status", stat); + return error; + } drive->id->dma_ultra &= ~0xFF00; drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; + if (speed > XFER_PIO_4) { + outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2); + } else { + outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2); + } + switch(speed) { -#if 0 - case XFER_UDMA_6: drive->id->dma_ultra |= 0x1010; break; - case XFER_UDMA_5: drive->id->dma_ultra |= 0x1010; break; -#endif + case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break; + case XFER_UDMA_6: drive->id->dma_ultra |= 0x4040; break; + case XFER_UDMA_5: drive->id->dma_ultra |= 0x2020; break; case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break; case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break; case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break; @@ -290,11 +302,10 @@ case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break; default: break; } - return(err); + return error; } EXPORT_SYMBOL(ide_driveid_update); -EXPORT_SYMBOL(ide_wait_noerr); EXPORT_SYMBOL(ide_ata66_check); EXPORT_SYMBOL(set_transfer); EXPORT_SYMBOL(ide_config_drive_speed); diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.3.47/linux/drivers/block/ide-floppy.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/ide-floppy.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 + * linux/drivers/block/ide-floppy.c Version 0.9 Jul 4, 1999 * * Copyright (C) 1996 - 1999 Gadi Oxman */ @@ -1264,8 +1264,11 @@ blocks = descriptor->blocks = ntohl (descriptor->blocks); length = descriptor->length = ntohs (descriptor->length); if (!i && descriptor->dc == CAPACITY_CURRENT) { - if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t))) - printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size\n", drive->name, blocks * length / 1024, blocks, length); + if (memcmp (descriptor, &floppy->capacity, sizeof (idefloppy_capacity_descriptor_t))) { + printk (KERN_INFO "%s: %dkB, %d blocks, %d sector size, %s \n", + drive->name, blocks * length / 1024, blocks, length, + drive->using_dma ? ", DMA":""); + } floppy->capacity = *descriptor; if (!length || length % 512) printk (KERN_ERR "%s: %d bytes block size not supported\n", drive->name, length); diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c --- v2.3.47/linux/drivers/block/ide-pci.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/block/ide-pci.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999 + * linux/drivers/block/ide-pci.c Version 1.04 July 27, 1999 * * Copyright (c) 1998-1999 Andre Hedrick * @@ -31,6 +31,7 @@ #define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) #define DEVID_PIIX4E ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1}) #define DEVID_PIIX4U ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1}) +#define DEVID_PIIX4U2 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1}) #define DEVID_VIA_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561}) #define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) #define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246}) @@ -95,13 +96,19 @@ #endif #ifdef CONFIG_BLK_DEV_AMD7409 +extern unsigned int pci_init_amd7409(struct pci_dev *, const char *); extern unsigned int ata66_amd7409(ide_hwif_t *); extern void ide_init_amd7409(ide_hwif_t *); +extern void ide_dmacapable_amd7409(ide_hwif_t *, unsigned long); +#define PCI_AMD7409 &pci_init_amd7409 #define ATA66_AMD7409 &ata66_amd7409 #define INIT_AMD7409 &ide_init_amd7409 +#define DMA_AMD7409 &ide_dmacapable_amd7409 #else +#define PCI_AMD7409 NULL #define ATA66_AMD7409 NULL #define INIT_AMD7409 NULL +#define DMA_AMD7409 NULL #endif #ifdef CONFIG_BLK_DEV_CMD64X @@ -135,11 +142,11 @@ #ifdef CONFIG_BLK_DEV_CS5530 extern unsigned int pci_init_cs5530(struct pci_dev *, const char *); extern void ide_init_cs5530(ide_hwif_t *); -#define INIT_CS5530 &ide_init_cs5530 #define PCI_CS5530 &pci_init_cs5530 +#define INIT_CS5530 &ide_init_cs5530 #else -#define INIT_CS5530 NULL #define PCI_CS5530 NULL +#define INIT_CS5530 NULL #endif #ifdef CONFIG_BLK_DEV_HPT34X @@ -149,7 +156,7 @@ #define INIT_HPT34X &ide_init_hpt34x #else #define PCI_HPT34X NULL -#define INIT_HPT34X NULL +#define INIT_HPT34X IDE_IGNORE #endif #ifdef CONFIG_BLK_DEV_HPT366 @@ -289,6 +296,7 @@ {DEVID_PIIX4, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4E, "PIIX4", PCI_PIIX, NULL, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIX4U, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, + {DEVID_PIIX4U2, "PIIX4", PCI_PIIX, ATA66_PIIX, INIT_PIIX, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_VIA_IDE, "VIA_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_VP_IDE, "VP_IDE", PCI_VIA82CXXX, ATA66_VIA82CXXX,INIT_VIA82CXXX, DMA_VIA82CXXX, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0 }, {DEVID_PDC20246,"PDC20246", PCI_PDC202XX, NULL, INIT_PDC202XX, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16 }, @@ -318,7 +326,7 @@ {DEVID_CY82C693,"CY82C693", PCI_CY82C693, NULL, INIT_CY82C693, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_HINT, "HINT_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, {DEVID_CS5530, "CS5530", PCI_CS5530, NULL, INIT_CS5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }, - {DEVID_AMD7409, "AMD7409", NULL, ATA66_AMD7409, INIT_AMD7409, NULL, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, + {DEVID_AMD7409, "AMD7409", PCI_AMD7409, ATA66_AMD7409, INIT_AMD7409, DMA_AMD7409, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0 }, {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }}; /* @@ -329,27 +337,6 @@ static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name) { switch(dev->device) { - case PCI_DEVICE_ID_TTI_HPT343: - { - int i; - unsigned long hpt34xIoBase = dev->resource[4].start; - unsigned short pcicmd = 0; - - pci_write_config_byte(dev, 0x80, 0x00); - pci_read_config_word(dev, PCI_COMMAND, &pcicmd); - if (!(pcicmd & PCI_COMMAND_MEMORY)) { - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); - } else { - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0); - } - - dev->resource[0].start = (hpt34xIoBase + 0x20); - dev->resource[1].start = (hpt34xIoBase + 0x34); - dev->resource[2].start = (hpt34xIoBase + 0x28); - dev->resource[3].start = (hpt34xIoBase + 0x3c); - for(i=0; i<4; i++) - dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; - } case PCI_DEVICE_ID_TTI_HPT366: case PCI_DEVICE_ID_PROMISE_20246: case PCI_DEVICE_ID_PROMISE_20262: @@ -535,17 +522,8 @@ #endif } if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) { - /* - * Since there are two cards that report almost identically, - * the only discernable difference is the values - * reported in pcicmd. - * Booting-BIOS card or HPT363 :: pcicmd == 0x07 - * Non-bootable card or HPT343 :: pcicmd == 0x05 - */ - if (pcicmd & PCI_COMMAND_MEMORY) { - printk("%s: is IDE Express HPT363.\n", d->name); - d->bootable = OFF_BOARD; - } + /* see comments in hpt34x.c on why..... */ + d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD; } /* * Set up the IDE ports @@ -618,9 +596,7 @@ if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) || IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) || -#ifdef CONFIG_BLK_DEV_HPT34X IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) || -#endif /* CONFIG_BLK_DEV_HPT34X */ IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) || IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) || diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.3.47/linux/drivers/block/ide-probe.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/block/ide-probe.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999 + * linux/drivers/block/ide-probe.c Version 1.05 July 3, 1999 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -57,7 +57,7 @@ ide__sti(); /* local CPU only */ ide_fix_driveid(id); if (!drive->forced_lun) - drive->last_lun = id->word126 & 0x7; + drive->last_lun = id->last_lun & 0x7; #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA) /* * EATA SCSI controllers do a hardware ATA emulation: @@ -395,6 +395,56 @@ } /* + * Calculate the region that this interface occupies, + * handling interfaces where the registers may not be + * ordered sanely. We deal with the CONTROL register + * separately. + */ +static int hwif_check_regions (ide_hwif_t *hwif) +{ + int region_errors = 0; + + region_errors = ide_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_ERROR_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_LCYL_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_HCYL_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_SELECT_OFFSET], 1); + region_errors += ide_check_region(hwif->io_ports[IDE_STATUS_OFFSET], 1); + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + region_errors += ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + if (hwif->io_ports[IDE_IRQ_OFFSET]) + region_errors += ide_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1); + + return(region_errors); +} + +static void hwif_register (ide_hwif_t *hwif) +{ + if (hwif->io_ports[IDE_DATA_OFFSET]) + ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_ERROR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_NSECTOR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_SECTOR_OFFSET]) + ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_LCYL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_HCYL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_SELECT_OFFSET]) + ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_STATUS_OFFSET]) + ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name); + if (hwif->io_ports[IDE_IRQ_OFFSET]) + ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name); +} + +/* * This routine only knows how to look for drive units 0 and 1 * on an interface, so any setting of MAX_DRIVES > 2 won't work here. */ @@ -403,12 +453,6 @@ unsigned int unit; unsigned long flags; - ide_ioreg_t ide_control_reg = hwif->io_ports[IDE_CONTROL_OFFSET]; - ide_ioreg_t region_low = hwif->io_ports[IDE_DATA_OFFSET]; - ide_ioreg_t region_high = region_low; - unsigned int region_request = 8; - int i; - if (hwif->noprobe) return; if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) { @@ -417,30 +461,11 @@ probe_cmos_for_drives (hwif); } - /* - * Calculate the region that this interface occupies, - * handling interfaces where the registers may not be - * ordered sanely. We deal with the CONTROL register - * separately. - */ - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - if (hwif->io_ports[i]) { - if (hwif->io_ports[i] < region_low) - region_low = hwif->io_ports[i]; - if (hwif->io_ports[i] > region_high) - region_high = hwif->io_ports[i]; - } - } - region_request = (region_high - region_low); - if (region_request == 0x0007) - region_request++; if ((hwif->chipset != ide_4drives || !hwif->mate->present) && #if CONFIG_BLK_DEV_PDC4030 (hwif->chipset != ide_pdc4030 || hwif->channel == 0) && #endif /* CONFIG_BLK_DEV_PDC4030 */ - (ide_check_region(region_low, region_request) || - (ide_control_reg && ide_check_region(ide_control_reg,1)))) - { + (hwif_check_regions(hwif))) { int msgout = 0; for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; @@ -467,20 +492,18 @@ if (drive->present && !hwif->present) { hwif->present = 1; if (hwif->chipset != ide_4drives || !hwif->mate->present) { - ide_request_region(region_low, region_request, hwif->name); - if (ide_control_reg) - ide_request_region(ide_control_reg, 1, hwif->name); + hwif_register(hwif); } } } - if (ide_control_reg && hwif->reset) { + if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) { unsigned long timeout = jiffies + WAIT_WORSTCASE; byte stat; printk("%s: reset\n", hwif->name); - OUT_BYTE(12, ide_control_reg); + OUT_BYTE(12, hwif->io_ports[IDE_CONTROL_OFFSET]); udelay(10); - OUT_BYTE(8, ide_control_reg); + OUT_BYTE(8, hwif->io_ports[IDE_CONTROL_OFFSET]); do { ide_delay_50ms(); stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); @@ -594,7 +617,11 @@ * Allocate the irq, if not already obtained for another hwif */ if (!match || match->irq != hwif->irq) { +#ifdef CONFIG_IDEPCI_SHARE_IRQ + int sa = (hwif->chipset == ide_pci) ? SA_SHIRQ : SA_INTERRUPT; +#else /* !CONFIG_IDEPCI_SHARE_IRQ */ int sa = (hwif->chipset == ide_pci) ? SA_INTERRUPT|SA_SHIRQ : SA_INTERRUPT; +#endif /* CONFIG_IDEPCI_SHARE_IRQ */ if (ide_request_irq(hwif->irq, &ide_intr, sa, hwif->name, hwgroup)) { if (!match) kfree(hwgroup); @@ -784,20 +811,18 @@ return (hwif->present = 0); } - if (init_irq (hwif)) { + if (init_irq(hwif)) { int i = hwif->irq; /* * It failed to initialise. Find the default IRQ for * this port and try that. */ - if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) - { + if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) { printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i); (void) unregister_blkdev (hwif->major, hwif->name); return (hwif->present = 0); } - if(init_irq (hwif)) - { + if (init_irq(hwif)) { printk("%s: probed IRQ %d and default IRQ %d failed.\n", hwif->name, i, hwif->irq); (void) unregister_blkdev (hwif->major, hwif->name); @@ -863,7 +888,8 @@ for (index = 0; index < MAX_HWIFS; ++index) if (probe[index]) hwif_init(&ide_hwifs[index]); - ide_register_module(&ideprobe_module); + if (!ide_probe) + ide_probe = &ideprobe_module; MOD_DEC_USE_COUNT; return 0; } @@ -882,6 +908,6 @@ void cleanup_module (void) { - ide_unregister_module(&ideprobe_module); + ide_probe = NULL; } #endif /* MODULE */ diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c --- v2.3.47/linux/drivers/block/ide-proc.c Tue Dec 7 09:32:43 1999 +++ linux/drivers/block/ide-proc.c Sat Feb 26 20:32:13 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998 + * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998 * * Copyright (C) 1997-1998 Mark Lord */ @@ -73,21 +73,46 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif +#ifdef CONFIG_BLK_DEV_AEC6210 +extern byte aec6210_proc; +int (*aec6210_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_AEC6210 */ #ifdef CONFIG_BLK_DEV_ALI15X3 extern byte ali_proc; int (*ali_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_ALI15X3 */ - +#ifdef CONFIG_BLK_DEV_AMD7409 +extern byte amd7409_proc; +int (*amd7409_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_AMD7409 */ +#ifdef CONFIG_BLK_DEV_CMD64X +extern byte cmd64x_proc; +int (*cmd64x_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_CMD64X */ +#ifdef CONFIG_BLK_DEV_CS5530 +extern byte cs5530_proc; +int (*cs5530_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_CS5530 */ +#ifdef CONFIG_BLK_DEV_HPT34X +extern byte hpt34x_proc; +int (*hpt34x_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_HPT34X */ +#ifdef CONFIG_BLK_DEV_HPT366 +extern byte hpt366_proc; +int (*hpt366_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_PDC202XX +extern byte pdc202xx_proc; +int (*pdc202xx_display_info)(char *, char **, off_t, int) = NULL; +#endif /* CONFIG_BLK_DEV_PDC202XX */ #ifdef CONFIG_BLK_DEV_PIIX extern byte piix_proc; int (*piix_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_PIIX */ - #ifdef CONFIG_BLK_DEV_SIS5513 extern byte sis_proc; int (*sis_display_info)(char *, char **, off_t, int) = NULL; #endif /* CONFIG_BLK_DEV_SIS5513 */ - #ifdef CONFIG_BLK_DEV_VIA82CXXX extern byte via_proc; int (*via_display_info)(char *, char **, off_t, int) = NULL; @@ -229,7 +254,7 @@ #endif /* CONFIG_BLK_DEV_IDEPCI */ if (for_real) { #if 0 - printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? 'PCI' : 'non-PCI', reg, val, digits); + printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? "PCI" : "non-PCI", reg, val, digits); #endif if (is_pci) { #ifdef CONFIG_BLK_DEV_IDEPCI @@ -349,7 +374,7 @@ while (p) { driver = (ide_driver_t *) p->info; - if (p->type == IDE_DRIVER_MODULE && driver) + if (driver) out += sprintf(out, "%s version %s\n", driver->name, driver->version); p = p->next; } @@ -775,10 +800,38 @@ create_proc_read_entry("drivers",0,proc_ide_root, proc_ide_read_drivers, NULL); +#ifdef CONFIG_BLK_DEV_AEC6210 + if ((aec6210_display_info) && (aec6210_proc)) + create_proc_info_entry("aec6210", 0, proc_ide_root, aec6210_display_info); +#endif /* CONFIG_BLK_DEV_AEC6210 */ #ifdef CONFIG_BLK_DEV_ALI15X3 if ((ali_display_info) && (ali_proc)) create_proc_info_entry("ali", 0, proc_ide_root, ali_display_info); #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_AMD7409 + if ((amd7409_display_info) && (amd7409_proc)) + create_proc_info_entry("amd7409", 0, proc_ide_root, amd7409_display_info); +#endif /* CONFIG_BLK_DEV_AMD7409 */ +#ifdef CONFIG_BLK_DEV_CMD64X + if ((cmd64x_display_info) && (cmd64x_proc)) + create_proc_info_entry("cmd64x", 0, proc_ide_root, cmd64x_display_info); +#endif /* CONFIG_BLK_DEV_CMD64X */ +#ifdef CONFIG_BLK_DEV_CS5530 + if ((cs5530_display_info) && (cs5530_proc)) + create_proc_info_entry("cs5530", 0, proc_ide_root, cs5530_display_info); +#endif /* CONFIG_BLK_DEV_CS5530 */ +#ifdef CONFIG_BLK_DEV_HPT34X + if ((hpt34x_display_info) && (hpt34x_proc)) + create_proc_info_entry("", 0, proc_ide_root, hpt34x_display_info); +#endif /* CONFIG_BLK_DEV_HPT34X */ +#ifdef CONFIG_BLK_DEV_HPT366 + if ((hpt366_display_info) && (hpt366_proc)) + create_proc_info_entry("", 0, proc_ide_root, hpt366_display_info); +#endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_PDC202XX + if ((pdc202xx_display_info) && (pdc202xx_proc)) + create_proc_info_entry("pdc202xx", 0, proc_ide_root, pdc202xx_display_info); +#endif /* CONFIG_BLK_DEV_PDC202XX */ #ifdef CONFIG_BLK_DEV_PIIX if ((piix_display_info) && (piix_proc)) create_proc_info_entry("piix", 0, proc_ide_root, piix_display_info); @@ -799,10 +852,38 @@ * Mmmm.. does this free up all resources, * or do we need to do a more proper cleanup here ?? */ +#ifdef CONFIG_BLK_DEV_AEC6210 + if ((aec6210_display_info) && (aec6210_proc)) + remove_proc_entry("ide/aec6210",0); +#endif /* CONFIG_BLK_DEV_AEC6210 */ #ifdef CONFIG_BLK_DEV_ALI15X3 if ((ali_display_info) && (ali_proc)) remove_proc_entry("ide/ali",0); #endif /* CONFIG_BLK_DEV_ALI15X3 */ +#ifdef CONFIG_BLK_DEV_AMD7409 + if ((amd7409_display_info) && (amd7409_proc)) + remove_proc_entry("ide/amd7409",0); +#endif /* CONFIG_BLK_DEV_AMD7409 */ +#ifdef CONFIG_BLK_DEV_CMD64X + if ((cmd64x_display_info) && (cmd64x_proc)) + remove_proc_entry("ide/cmd64x",0); +#endif /* CONFIG_BLK_DEV_CMD64X */ +#ifdef CONFIG_BLK_DEV_CS5530 + if ((cs5530_display_info) && (cs5530_proc)) + remove_proc_entry("ide/cs5530",0); +#endif /* CONFIG_BLK_DEV_CS5530 */ +#ifdef CONFIG_BLK_DEV_HPT34X + if ((hpt34x_display_info) && (hpt34x_proc)) + remove_proc_entry("ide/hpt34x",0); +#endif /* CONFIG_BLK_DEV_HPT34X */ +#ifdef CONFIG_BLK_DEV_HPT366 + if ((hpt366_display_info) && (hpt366_proc)) + remove_proc_entry("ide/hpt366",0); +#endif /* CONFIG_BLK_DEV_HPT366 */ +#ifdef CONFIG_BLK_DEV_PDC202XX + if ((pdc202xx_display_info) && (pdc202xx_proc)) + remove_proc_entry("ide/pdc202xx",0); +#endif /* CONFIG_BLK_DEV_PDC202XX */ #ifdef CONFIG_BLK_DEV_PIIX if ((piix_display_info) && (piix_proc)) remove_proc_entry("ide/piix",0); diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.3.47/linux/drivers/block/ide-tape.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/ide-tape.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999 + * linux/drivers/block/ide-tape.c Version 1.16f Dec 15, 1999 * * Copyright (C) 1995 - 1999 Gadi Oxman * @@ -411,12 +411,12 @@ #include -#define NO_LONGER_REQUIRE (1) +#define NO_LONGER_REQUIRED (1) /* * OnStream support */ -#define ONSTREAM_DEBUG (1) +#define ONSTREAM_DEBUG (0) #define OS_CONFIG_PARTITION (0xff) #define OS_DATA_PARTITION (0) #define OS_PARTITION_VERSION (1) @@ -543,6 +543,7 @@ /* * The following are used to debug the driver: * + * Setting IDETAPE_DEBUG_INFO to 1 will report device capabilities. * Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control. * Setting IDETAPE_DEBUG_BUGS to 1 will enable self-sanity checks in * some places. @@ -557,7 +558,9 @@ * is verified to be stable enough. This will make it much more * esthetic. */ +#define IDETAPE_DEBUG_INFO 0 #define IDETAPE_DEBUG_LOG 1 +#define IDETAPE_DEBUG_LOG_VERBOSE 0 #define IDETAPE_DEBUG_BUGS 1 /* @@ -700,9 +703,10 @@ */ typedef struct { unsigned page_code :6; /* Page code - Should be 0x2a */ - unsigned reserved1_67 :2; - u8 page_length; /* Page Length - Should be 0x12 */ - u8 reserved2, reserved3; + __u8 reserved0_6 :1; + __u8 ps :1; /* parameters saveable */ + __u8 page_length; /* Page Length - Should be 0x12 */ + __u8 reserved2, reserved3; unsigned ro :1; /* Read Only Mode */ unsigned reserved4_1234 :4; unsigned sprev :1; /* Supports SPACE in the reverse direction */ @@ -716,7 +720,8 @@ unsigned locked :1; /* The volume is locked */ unsigned prevent :1; /* The device defaults in the prevent state after power up */ unsigned eject :1; /* The device can eject the volume */ - unsigned reserved6_45 :2; /* Reserved */ + __u8 disconnect :1; /* The device can break request > ctl */ + __u8 reserved6_5 :1; unsigned ecc :1; /* Supports error correction */ unsigned cmprs :1; /* Supports data compression */ unsigned reserved7_0 :1; @@ -726,12 +731,12 @@ unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ /* transfers for slow buffer memory ??? */ /* Also 32768 block size in some cases */ - u16 max_speed; /* Maximum speed supported in KBps */ - u8 reserved10, reserved11; - u16 ctl; /* Continuous Transfer Limit in blocks */ - u16 speed; /* Current Speed, in KBps */ - u16 buffer_size; /* Buffer Size, in 512 bytes */ - u8 reserved18, reserved19; + __u16 max_speed; /* Maximum speed supported in KBps */ + __u8 reserved10, reserved11; + __u16 ctl; /* Continuous Transfer Limit in blocks */ + __u16 speed; /* Current Speed, in KBps */ + __u16 buffer_size; /* Buffer Size, in 512 bytes */ + __u8 reserved18, reserved19; } idetape_capabilities_page_t; /* @@ -741,8 +746,8 @@ unsigned page_code :6; /* Page code - Should be 0x30 */ unsigned reserved1_6 :1; unsigned ps :1; - u8 page_length; /* Page Length - Should be 2 */ - u8 reserved2; + __u8 page_length; /* Page Length - Should be 2 */ + __u8 reserved2; unsigned play32 :1; unsigned play32_5 :1; unsigned reserved2_23 :2; @@ -768,23 +773,23 @@ typedef struct { unsigned error_code :7; /* Current of deferred errors */ unsigned valid :1; /* The information field conforms to QIC-157C */ - u8 reserved1 :8; /* Segment Number - Reserved */ + __u8 reserved1 :8; /* Segment Number - Reserved */ unsigned sense_key :4; /* Sense Key */ unsigned reserved2_4 :1; /* Reserved */ unsigned ili :1; /* Incorrect Length Indicator */ unsigned eom :1; /* End Of Medium */ unsigned filemark :1; /* Filemark */ - u32 information __attribute__ ((packed)); - u8 asl; /* Additional sense length (n-7) */ - u32 command_specific; /* Additional command specific information */ - u8 asc; /* Additional Sense Code */ - u8 ascq; /* Additional Sense Code Qualifier */ - u8 replaceable_unit_code; /* Field Replaceable Unit Code */ + __u32 information __attribute__ ((packed)); + __u8 asl; /* Additional sense length (n-7) */ + __u32 command_specific; /* Additional command specific information */ + __u8 asc; /* Additional Sense Code */ + __u8 ascq; /* Additional Sense Code Qualifier */ + __u8 replaceable_unit_code; /* Field Replaceable Unit Code */ unsigned sk_specific1 :7; /* Sense Key Specific */ unsigned sksv :1; /* Sense Key Specific information is valid */ - u8 sk_specific2; /* Sense Key Specific */ - u8 sk_specific3; /* Sense Key Specific */ - u8 pad[2]; /* Padding to 20 bytes */ + __u8 sk_specific2; /* Sense Key Specific */ + __u8 sk_specific3; /* Sense Key Specific */ + __u8 pad[2]; /* Padding to 20 bytes */ } idetape_request_sense_result_t; @@ -1247,13 +1252,13 @@ unsigned reserved3_45 :2; /* Reserved */ unsigned reserved3_6 :1; /* TrmIOP - Reserved */ unsigned reserved3_7 :1; /* AENC - Reserved */ - u8 additional_length; /* Additional Length (total_length-4) */ - u8 rsv5, rsv6, rsv7; /* Reserved */ - u8 vendor_id[8]; /* Vendor Identification */ - u8 product_id[16]; /* Product Identification */ - u8 revision_level[4]; /* Revision Level */ - u8 vendor_specific[20]; /* Vendor Specific - Optional */ - u8 reserved56t95[40]; /* Reserved - Optional */ + __u8 additional_length; /* Additional Length (total_length-4) */ + __u8 rsv5, rsv6, rsv7; /* Reserved */ + __u8 vendor_id[8]; /* Vendor Identification */ + __u8 product_id[16]; /* Product Identification */ + __u8 revision_level[4]; /* Revision Level */ + __u8 vendor_specific[20]; /* Vendor Specific - Optional */ + __u8 reserved56t95[40]; /* Reserved - Optional */ /* Additional information may be returned */ } idetape_inquiry_result_t; @@ -1287,10 +1292,25 @@ * Mode Parameter Header for the MODE SENSE packet command */ typedef struct { - u8 mode_data_length; /* Length of the following data transfer */ - u8 medium_type; /* Medium Type */ - u8 dsp; /* Device Specific Parameter */ - u8 bdl; /* Block Descriptor Length */ + __u8 mode_data_length; /* Length of the following data transfer */ + __u8 medium_type; /* Medium Type */ + __u8 dsp; /* Device Specific Parameter */ + __u8 bdl; /* Block Descriptor Length */ +#if 0 + /* data transfer page */ + __u8 page_code :6; + __u8 reserved0_6 :1; + __u8 ps :1; /* parameters saveable */ + __u8 page_length; /* page Length == 0x02 */ + __u8 reserved2; + __u8 read32k :1; /* 32k blk size (data only) */ + __u8 read32k5 :1; /* 32.5k blk size (data&AUX) */ + __u8 reserved3_23 :2; + __u8 write32k :1; /* 32k blk size (data only) */ + __u8 write32k5 :1; /* 32.5k blk size (data&AUX) */ + __u8 reserved3_6 :1; + __u8 streaming :1; /* streaming mode enable */ +#endif } idetape_mode_parameter_header_t; /* @@ -1299,10 +1319,10 @@ * Support for block descriptors is optional. */ typedef struct { - u8 density_code; /* Medium density code */ - u8 blocks[3]; /* Number of blocks */ - u8 reserved4; /* Reserved */ - u8 length[3]; /* Block Length */ + __u8 density_code; /* Medium density code */ + __u8 blocks[3]; /* Number of blocks */ + __u8 reserved4; /* Reserved */ + __u8 length[3]; /* Block Length */ } idetape_parameter_block_descriptor_t; /* @@ -1312,16 +1332,16 @@ unsigned page_code :6; /* Page Code - Should be 0xf */ unsigned reserved0 :1; /* Reserved */ unsigned ps :1; - u8 page_length; /* Page Length - Should be 14 */ + __u8 page_length; /* Page Length - Should be 14 */ unsigned reserved2 :6; /* Reserved */ unsigned dcc :1; /* Data Compression Capable */ unsigned dce :1; /* Data Compression Enable */ unsigned reserved3 :5; /* Reserved */ unsigned red :2; /* Report Exception on Decompression */ unsigned dde :1; /* Data Decompression Enable */ - u32 ca; /* Compression Algorithm */ - u32 da; /* Decompression Algorithm */ - u8 reserved[4]; /* Reserved */ + __u32 ca; /* Compression Algorithm */ + __u32 da; /* Decompression Algorithm */ + __u8 reserved[4]; /* Reserved */ } idetape_data_compression_page_t; /* @@ -1331,16 +1351,16 @@ unsigned page_code :6; /* Page Code - Should be 0x11 */ unsigned reserved1_6 :1; /* Reserved */ unsigned ps :1; - u8 page_length; /* Page Length - Should be 6 */ - u8 map; /* Maximum Additional Partitions - Should be 0 */ - u8 apd; /* Additional Partitions Defined - Should be 0 */ + __u8 page_length; /* Page Length - Should be 6 */ + __u8 map; /* Maximum Additional Partitions - Should be 0 */ + __u8 apd; /* Additional Partitions Defined - Should be 0 */ unsigned reserved4_012 :3; /* Reserved */ unsigned psum :2; /* Should be 0 */ unsigned idp :1; /* Should be 0 */ unsigned sdp :1; /* Should be 0 */ unsigned fdp :1; /* Fixed Data Partitions */ - u8 mfr; /* Medium Format Recognition */ - u8 reserved[2]; /* Reserved */ + __u8 mfr; /* Medium Format Recognition */ + __u8 reserved[2]; /* Reserved */ } idetape_medium_partition_page_t; /* @@ -1359,6 +1379,53 @@ static idetape_chrdev_t idetape_chrdevs[MAX_HWIFS * MAX_DRIVES]; static int idetape_chrdev_present = 0; +#if IDETAPE_DEBUG_LOG_VERBOSE + +/* + * DO NOT REMOVE, BUILDING A VERBOSE DEBUG SCHEME FOR ATAPI + */ + +char *idetape_sense_key_verbose (byte idetape_sense_key) +{ + switch (idetape_sense_key) { + default: { + char buf[22]; + sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key); + return(buf); + } + + } +} + +char *idetape_command_key_verbose (byte idetape_command_key) +{ + switch (idetape_command_key) { + case IDETAPE_TEST_UNIT_READY_CMD: return("TEST_UNIT_READY_CMD"); + case IDETAPE_REWIND_CMD: return("REWIND_CMD"); + case IDETAPE_REQUEST_SENSE_CMD: return("REQUEST_SENSE_CMD"); + case IDETAPE_READ_CMD: return("READ_CMD"); + case IDETAPE_WRITE_CMD: return("WRITE_CMD"); + case IDETAPE_WRITE_FILEMARK_CMD: return("WRITE_FILEMARK_CMD"); + case IDETAPE_SPACE_CMD: return("SPACE_CMD"); + case IDETAPE_INQUIRY_CMD: return("INQUIRY_CMD"); + case IDETAPE_ERASE_CMD: return("ERASE_CMD") + case IDETAPE_MODE_SENSE_CMD: return("MODE_SENSE_CMD"); + case IDETAPE_MODE_SELECT_CMD: return("MODE_SELECT_CMD"); + case IDETAPE_LOAD_UNLOAD_CMD: return("LOAD_UNLOAD_CMD"); + case IDETAPE_PREVENT_CMD: return("PREVENT_CMD"); + case IDETAPE_LOCATE_CMD: return("LOCATE_CMD"); + case IDETAPE_READ_POSITION_CMD: return("READ_POSITION_CMD"); + case IDETAPE_READ_BUFFER_CMD: return("READ_BUFFER_CMD"); + case IDETAPE_SET_SPEED_CMD: return("SET_SPEED_CMD"); + default: { + char buf[20]; + sprintf(buf, "CMD (0x%02x)", idetape_command_key); + return(buf); + } + } +} +#endif /* IDETAPE_DEBUG_LOG_VERBOSE */ + /* * Too bad. The drive wants to send us data which we are not ready to accept. * Just throw it away. @@ -1523,6 +1590,14 @@ */ if (tape->debug_level >= 1) printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",pc->c[0],result->sense_key,result->asc,result->ascq); +#if IDETAPE_DEBUG_LOG_VERBOSE + if (tape->debug_level >= 1) + printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n", + idetape_command_key_verbose((byte) pc->c[0]), + result->sense_key, + result->asc, + result->ascq); +#endif /* IDETAPE_DEBUG_LOG_VERBOSE */ #endif /* IDETAPE_DEBUG_LOG */ if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) { @@ -3833,7 +3908,7 @@ if (tape->onstream) { #if ONSTREAM_DEBUG if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %d\n", tape->name, test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)); + printk(KERN_INFO "ide-tape: %s: first_stage == NULL, pipeline error %ld\n", tape->name, (long)test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)); #endif clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); position = idetape_read_position(drive); @@ -5280,16 +5355,16 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id) { struct idetape_id_gcw gcw; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO unsigned short mask,i; -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_INFO */ if (!id) return 0; *((unsigned short *) &gcw) = id->config; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n"); printk (KERN_INFO "ide-tape: Protocol Type: "); switch (gcw.protocol) { @@ -5377,7 +5452,7 @@ } else printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n"); -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_INFO */ /* Check that we can support this device */ @@ -5462,12 +5537,12 @@ header = (idetape_mode_parameter_header_t *) pc.buffer; bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl); -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO printk(KERN_INFO "ide-tape: 32KB play back: %s\n", bs->play32 ? "Yes" : "No"); printk(KERN_INFO "ide-tape: 32.5KB play back: %s\n", bs->play32_5 ? "Yes" : "No"); printk(KERN_INFO "ide-tape: 32KB record: %s\n", bs->record32 ? "Yes" : "No"); printk(KERN_INFO "ide-tape: 32.5KB record: %s\n", bs->record32_5 ? "Yes" : "No"); -#endif +#endif /* IDETAPE_DEBUG_INFO */ /* * Configure default auto columns mode, 32.5KB block size @@ -5587,7 +5662,7 @@ else if (tape->onstream && capabilities->blk32768) tape->tape_block_size = 32768; -#if IDETAPE_DEBUG_LOG +#if IDETAPE_DEBUG_INFO printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n"); printk (KERN_INFO "ide-tape: Mode Parameter Header:\n"); printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length); @@ -5615,7 +5690,7 @@ printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl); printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed); printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512); -#endif /* IDETAPE_DEBUG_LOG */ +#endif /* IDETAPE_DEBUG_INFO */ } static void idetape_add_settings (ide_drive_t *drive) diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.3.47/linux/drivers/block/ide.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/ide.c Sat Feb 26 20:32:14 2000 @@ -186,6 +186,7 @@ * ide_modules keeps track of the available IDE chipset/probe/driver modules. */ ide_module_t *ide_modules = NULL; +ide_module_t *ide_probe = NULL; /* * This is declared extern in ide.h, for access by other IDE modules: @@ -281,7 +282,7 @@ * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them. */ #define MAGIC_COOKIE 0x12345678 -static void init_ide_data (void) +static void __init init_ide_data (void) { unsigned int index; static unsigned long magic_cookie = MAGIC_COOKIE; @@ -1093,13 +1094,18 @@ #endif block = rq->sector; blockend = block + rq->nr_sectors; - if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { - printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, - (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); - goto kill_rq; +#if 0 + if ((rq->cmd == READ || rq->cmd == WRITE) && + (drive->media == ide_disk || drive->media == ide_floppy)) +#endif + { + if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) { + printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name, + (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors); + goto kill_rq; + } + block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0; } - block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0; - /* Yecch - this will shift the entire interval, possibly killing some innocent following sector */ if (block == 0 && drive->remap_0_to_1 == 1) @@ -1409,9 +1415,9 @@ } } else { ide_drive_t *drive = hwgroup->drive; - hwgroup->handler = NULL; if (!drive) { printk("ide_timer_expiry: hwgroup->drive was NULL\n"); + hwgroup->handler = NULL; } else { ide_hwif_t *hwif; ide_startstop_t startstop; @@ -1429,6 +1435,7 @@ return; } } + hwgroup->handler = NULL; /* * We need to simulate a real interrupt when invoking * the handler() function, which means we need to globally @@ -1436,7 +1443,7 @@ */ spin_unlock(&io_request_lock); hwif = HWIF(drive); - disable_irq(hwif->irq); + disable_irq(hwif->irq); /* disable_irq_nosync ?? */ __cli(); /* local CPU only, as if we were handling an interrupt */ if (hwgroup->poll_timeout != 0) { startstop = handler(drive); @@ -1802,23 +1809,33 @@ } } -static void ide_init_module (int type) +static void ide_probe_module (void) +{ + if (!ide_probe) { +#ifdef CONFIG_KMOD + (void) request_module("ide-probe-mod"); +#endif /* CONFIG_KMOD */ + } else { + (void) ide_probe->init(); + } + revalidate_drives(); +} + +static void ide_driver_module (void) { - int found = 0; + int index; ide_module_t *module = ide_modules; - + + for (index = 0; index < MAX_HWIFS; ++index) + if (ide_hwifs[index].present) + goto search; + ide_probe_module(); +search: while (module) { - if (module->type == type) { - found = 1; - (void) module->init(); - } + (void) module->init(); module = module->next; } revalidate_drives(); -#ifdef CONFIG_KMOD - if (!found && type == IDE_PROBE_MODULE) - (void) request_module("ide-probe-mod"); -#endif /* CONFIG_KMOD */ } static int ide_open (struct inode * inode, struct file * filp) @@ -1830,7 +1847,7 @@ return -ENXIO; MOD_INC_USE_COUNT; if (drive->driver == NULL) - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); #ifdef CONFIG_KMOD if (drive->driver == NULL) { if (drive->media == ide_disk) @@ -1881,9 +1898,9 @@ if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) goto abort; strncpy(drive->driver_req, driver, 9); - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); drive->driver_req[0] = 0; - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver)) return 0; abort: @@ -1897,6 +1914,35 @@ }; #endif +/* + * Note that we only release the standard ports, + * and do not even try to handle any extra ports + * allocated for weird IDE interface chipsets. + */ +void hwif_unregister (ide_hwif_t *hwif) +{ + if (hwif->io_ports[IDE_DATA_OFFSET]) + ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1); + if (hwif->io_ports[IDE_ERROR_OFFSET]) + ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1); + if (hwif->io_ports[IDE_NSECTOR_OFFSET]) + ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1); + if (hwif->io_ports[IDE_SECTOR_OFFSET]) + ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1); + if (hwif->io_ports[IDE_LCYL_OFFSET]) + ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1); + if (hwif->io_ports[IDE_HCYL_OFFSET]) + ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1); + if (hwif->io_ports[IDE_SELECT_OFFSET]) + ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1); + if (hwif->io_ports[IDE_STATUS_OFFSET]) + ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1); + if (hwif->io_ports[IDE_CONTROL_OFFSET]) + ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + if (hwif->io_ports[IDE_IRQ_OFFSET]) + ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1); +} + void ide_unregister (unsigned int index) { struct gendisk *gd, **gdp; @@ -1967,9 +2013,7 @@ * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. */ - ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8); - if (hwif->io_ports[IDE_CONTROL_OFFSET]) - ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + hwif_unregister(hwif); /* * Remove us from the hwgroup, and free @@ -2036,23 +2080,28 @@ kfree (gd->flags); kfree(gd); } - old_hwif = *hwif; + old_hwif = *hwif; init_hwif_data (index); /* restore hwif data to pristine status */ - hwif->hwgroup = old_hwif.hwgroup; - hwif->tuneproc = old_hwif.tuneproc; - hwif->resetproc = old_hwif.resetproc; - hwif->dmaproc = old_hwif.dmaproc; - hwif->dma_base = old_hwif.dma_base; - hwif->dma_extra = old_hwif.dma_extra; - hwif->config_data = old_hwif.config_data; - hwif->select_data = old_hwif.select_data; - hwif->irq = old_hwif.irq; - hwif->major = old_hwif.major; - hwif->proc = old_hwif.proc; - hwif->udma_four = old_hwif.udma_four; - hwif->chipset = old_hwif.chipset; - hwif->pci_dev = old_hwif.pci_dev; - hwif->pci_devid = old_hwif.pci_devid; + hwif->hwgroup = old_hwif.hwgroup; + hwif->tuneproc = old_hwif.tuneproc; + hwif->selectproc = old_hwif.selectproc; + hwif->resetproc = old_hwif.resetproc; + hwif->dmaproc = old_hwif.dmaproc; + hwif->dma_base = old_hwif.dma_base; + hwif->dma_extra = old_hwif.dma_extra; + hwif->config_data = old_hwif.config_data; + hwif->select_data = old_hwif.select_data; + hwif->proc = old_hwif.proc; + hwif->irq = old_hwif.irq; + hwif->major = old_hwif.major; + hwif->chipset = old_hwif.chipset; + hwif->autodma = old_hwif.autodma; + hwif->udma_four = old_hwif.udma_four; +#ifdef CONFIG_BLK_DEV_IDEPCI + hwif->pci_dev = old_hwif.pci_dev; + hwif->pci_devid = old_hwif.pci_devid; +#endif /* CONFIG_BLK_DEV_IDEPCI */ + abort: restore_flags(flags); /* all CPUs */ } @@ -2087,6 +2136,7 @@ } } hw->irq = irq; + hw->dma = NO_DMA; hw->ack_intr = ack_intr; } @@ -2126,11 +2176,11 @@ hwif->noprobe = 0; if (!initializing) { - ide_init_module(IDE_PROBE_MODULE); + ide_probe_module(); #ifdef CONFIG_PROC_FS create_proc_ide_interfaces(); #endif - ide_init_module(IDE_DRIVER_MODULE); + ide_driver_module(); } if (hwifp) @@ -2750,7 +2800,7 @@ if (!strcmp(s, "ide=doubler")) { extern int ide_doubler; - printk("ide: Enabled support for IDE doublers\n"); + printk(" : Enabled support for IDE doublers\n"); ide_doubler = 1; return 0; } @@ -2759,12 +2809,14 @@ #ifdef CONFIG_BLK_DEV_IDEPCI if (!strcmp(s, "ide=reverse")) { ide_scan_direction = 1; - printk("ide: Enabled support for IDE inverse scan order.\n"); + printk(" : Enabled support for IDE inverse scan order.\n"); return 0; } #endif /* CONFIG_BLK_DEV_IDEPCI */ +#ifndef CONFIG_BLK_DEV_IDEPCI init_ide_data (); +#endif /* CONFIG_BLK_DEV_IDEPCI */ /* * Look for drive options: "hdx=" @@ -3176,7 +3228,7 @@ #if defined(__mc68000__) || defined(CONFIG_APUS) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { ide_get_lock(&ide_lock, NULL, NULL); /* for atari only */ - disable_irq(ide_hwifs[0].irq); + disable_irq(ide_hwifs[0].irq); /* disable_irq_nosync ?? */ } #endif /* __mc68000__ || CONFIG_APUS */ @@ -3293,10 +3345,6 @@ { unsigned int unit, index, i; - for (index = 0; index < MAX_HWIFS; ++index) - if (ide_hwifs[index].present) goto search; - ide_init_module(IDE_PROBE_MODULE); -search: for (index = 0, i = 0; index < MAX_HWIFS; ++index) { ide_hwif_t *hwif = &ide_hwifs[index]; if (!hwif->present) @@ -3327,8 +3375,16 @@ setup_driver_defaults(drive); restore_flags(flags); /* all CPUs */ if (drive->autotune != 2) { - if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) + if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) { + /* + * Force DMAing for the beginning of the check. + * Some chipsets appear to do interesting things, + * if not checked and cleared. + * PARANOIA!!! + */ + (void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive)); (void) (HWIF(drive)->dmaproc(ide_dma_check, drive)); + } drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap); drive->nice1 = 1; } @@ -3400,6 +3456,7 @@ /* * Probe module */ +EXPORT_SYMBOL(ide_probe); EXPORT_SYMBOL(drive_is_flashcard); EXPORT_SYMBOL(ide_timer_expiry); EXPORT_SYMBOL(ide_intr); @@ -3474,7 +3531,7 @@ EXPORT_SYMBOL(ide_register); EXPORT_SYMBOL(ide_unregister); EXPORT_SYMBOL(ide_setup_ports); - +EXPORT_SYMBOL(hwif_unregister); EXPORT_SYMBOL(get_info_ptr); EXPORT_SYMBOL(current_capacity); @@ -3539,13 +3596,9 @@ { int index; - for (index = 0; index < MAX_HWIFS; ++index) { + for (index = 0; index < MAX_HWIFS; ++index) ide_unregister(index); -#ifdef CONFIG_BLK_DEV_IDEDMA - if (ide_hwifs[index].dma_base) - (void) ide_release_dma(&ide_hwifs[index]); -#endif /* CONFIG_BLK_DEV_IDEDMA */ - } + #ifdef CONFIG_PROC_FS proc_ide_destroy(); #endif diff -u --recursive --new-file v2.3.47/linux/drivers/block/ide_modes.h linux/drivers/block/ide_modes.h --- v2.3.47/linux/drivers/block/ide_modes.h Wed Aug 18 16:43:30 1999 +++ linux/drivers/block/ide_modes.h Sat Feb 26 20:46:00 2000 @@ -1,10 +1,11 @@ -#ifndef _IDE_MODES_H -#define _IDE_MODES_H /* * linux/drivers/block/ide_modes.h * * Copyright (C) 1996 Linus Torvalds, Igor Abramov, and Mark Lord */ + +#ifndef _IDE_MODES_H +#define _IDE_MODES_H #include diff -u --recursive --new-file v2.3.47/linux/drivers/block/linear.c linux/drivers/block/linear.c --- v2.3.47/linux/drivers/block/linear.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/block/linear.c Wed Feb 23 09:13:52 2000 @@ -121,14 +121,15 @@ return 0; } -static int linear_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) +static int linear_make_request (request_queue_t *q, mddev_t *mddev, + int rw, struct buffer_head * bh) { linear_conf_t *conf = mddev_to_conf(mddev); struct linear_hash *hash; dev_info_t *tmp_dev; long block; - block = bh->b_blocknr * (bh->b_size >> 10); + block = bh->b_rsector >> 1; hash = conf->hash_table + (block / conf->smallest->size); if (block >= (hash->dev0->size + hash->dev0->offset)) { @@ -149,8 +150,7 @@ bh->b_rdev = tmp_dev->dev; bh->b_rsector = (block - tmp_dev->offset) << 1; - generic_make_request(rw, bh); - return 0; + return 1; } static int linear_status (char *page, mddev_t *mddev) diff -u --recursive --new-file v2.3.47/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.3.47/linux/drivers/block/ll_rw_blk.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/block/ll_rw_blk.c Fri Feb 25 10:28:13 2000 @@ -952,96 +952,122 @@ bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); } -void generic_make_request(int rw, struct buffer_head * bh) +static inline void buffer_IO_error(struct buffer_head * bh) { - request_queue_t * q; - unsigned long flags; + mark_buffer_clean(bh); + /* + * b_end_io has to clear the BH_Uptodate bitflag in the error case! + */ + bh->b_end_io(bh, 0); +} - q = blk_get_queue(bh->b_rdev); +int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) +{ + unsigned long flags; + int ret; + /* + * Resolve the mapping until finished. (drivers are + * still free to implement/resolve their own stacking + * by explicitly returning 0) + */ + + while (q->make_request_fn) { + ret = q->make_request_fn(q, rw, bh); + if (ret > 0) { + q = blk_get_queue(bh->b_rdev); + continue; + } + return ret; + } + /* + * Does the block device want us to queue + * the IO request? (normal case) + */ __make_request(q, rw, bh); - spin_lock_irqsave(&io_request_lock,flags); if (q && !q->plugged) (q->request_fn)(q); spin_unlock_irqrestore(&io_request_lock,flags); -} + return 0; +} /* This function can be used to request a number of buffers from a block device. Currently the only restriction is that all buffers must belong to the same device */ -static void __ll_rw_block(int rw, int nr, struct buffer_head * bh[],int haslock) +static void __ll_rw_block(int rw, int nr, struct buffer_head * bhs[], + int haslock) { + struct buffer_head *bh; + request_queue_t *q; unsigned int major; int correct_size; - request_queue_t *q; int i; - major = MAJOR(bh[0]->b_dev); - q = blk_get_queue(bh[0]->b_dev); + major = MAJOR(bhs[0]->b_dev); + q = blk_get_queue(bhs[0]->b_dev); if (!q) { printk(KERN_ERR "ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n", - kdevname(bh[0]->b_dev), bh[0]->b_blocknr); + kdevname(bhs[0]->b_dev), bhs[0]->b_blocknr); goto sorry; } /* Determine correct block size for this device. */ correct_size = BLOCK_SIZE; if (blksize_size[major]) { - i = blksize_size[major][MINOR(bh[0]->b_dev)]; + i = blksize_size[major][MINOR(bhs[0]->b_dev)]; if (i) correct_size = i; } /* Verify requested block sizes. */ for (i = 0; i < nr; i++) { - if (bh[i]->b_size != correct_size) { + bh = bhs[i]; + if (bh->b_size != correct_size) { printk(KERN_NOTICE "ll_rw_block: device %s: " "only %d-char blocks implemented (%u)\n", - kdevname(bh[0]->b_dev), - correct_size, bh[i]->b_size); + kdevname(bhs[0]->b_dev), + correct_size, bh->b_size); goto sorry; } } - if ((rw & WRITE) && is_read_only(bh[0]->b_dev)) { + if ((rw & WRITE) && is_read_only(bhs[0]->b_dev)) { printk(KERN_NOTICE "Can't write to read-only device %s\n", - kdevname(bh[0]->b_dev)); + kdevname(bhs[0]->b_dev)); goto sorry; } for (i = 0; i < nr; i++) { + bh = bhs[i]; + /* Only one thread can actually submit the I/O. */ if (haslock) { - if (!buffer_locked(bh[i])) + if (!buffer_locked(bh)) BUG(); } else { - if (test_and_set_bit(BH_Lock, &bh[i]->b_state)) + if (test_and_set_bit(BH_Lock, &bh->b_state)) continue; } - set_bit(BH_Req, &bh[i]->b_state); + set_bit(BH_Req, &bh->b_state); - if (q->make_request_fn) - q->make_request_fn(rw, bh[i]); - else { - bh[i]->b_rdev = bh[i]->b_dev; - bh[i]->b_rsector = bh[i]->b_blocknr*(bh[i]->b_size>>9); + /* + * First step, 'identity mapping' - RAID or LVM might + * further remap this. + */ + bh->b_rdev = bh->b_dev; + bh->b_rsector = bh->b_blocknr * (bh->b_size>>9); - generic_make_request(rw, bh[i]); - } + generic_make_request(q, rw, bh); } - return; sorry: - for (i = 0; i < nr; i++) { - mark_buffer_clean(bh[i]); /* remeber to refile it */ - clear_bit(BH_Uptodate, &bh[i]->b_state); - bh[i]->b_end_io(bh[i], 0); - } + for (i = 0; i < nr; i++) + buffer_IO_error(bhs[i]); return; } @@ -1176,9 +1202,8 @@ #ifdef CONFIG_BLK_DEV_FD floppy_init(); #else -#if !defined (__mc68000__) && !defined(CONFIG_PPC) && !defined(__sparc__)\ - && !defined(CONFIG_APUS) && !defined(__sh__) && !defined(__ia64__) - outb_p(0xc, 0x3f2); /* XXX do something with the floppy controller?? */ +#if defined(__i386__) /* Do we even need this? */ + outb_p(0xc, 0x3f2); #endif #endif #ifdef CONFIG_CDU31A diff -u --recursive --new-file v2.3.47/linux/drivers/block/lvm.c linux/drivers/block/lvm.c --- v2.3.47/linux/drivers/block/lvm.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/block/lvm.c Wed Feb 23 09:13:52 2000 @@ -192,7 +192,7 @@ static void lvm_dummy_device_request(request_queue_t *); #define DEVICE_REQUEST lvm_dummy_device_request -static void lvm_make_request_fn(int, struct buffer_head*); +static int lvm_make_request_fn(request_queue_t *, int, struct buffer_head*); static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); static int lvm_blk_open(struct inode *, struct file *); @@ -1292,14 +1292,14 @@ */ static int lvm_map(struct buffer_head *bh, int rw) { - int minor = MINOR(bh->b_dev); + int minor = MINOR(bh->b_rdev); int ret = 0; ulong index; ulong pe_start; ulong size = bh->b_size >> 9; - ulong rsector_tmp = bh->b_blocknr * size; + ulong rsector_tmp = bh->b_rsector; ulong rsector_sav; - kdev_t rdev_tmp = bh->b_dev; + kdev_t rdev_tmp = bh->b_rdev; kdev_t rdev_sav; lv_t *lv = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]; @@ -1513,11 +1513,10 @@ /* * make request function */ -static void lvm_make_request_fn(int rw, struct buffer_head *bh) +static int lvm_make_request_fn(request_queue_t *q, int rw, struct buffer_head *bh) { lvm_map(bh, rw); - if (bh->b_rdev != MD_MAJOR) generic_make_request(rw, bh); - return; + return 1; } diff -u --recursive --new-file v2.3.47/linux/drivers/block/macide.c linux/drivers/block/macide.c --- v2.3.47/linux/drivers/block/macide.c Tue Sep 7 12:14:06 1999 +++ linux/drivers/block/macide.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/macide.c -- Macintosh IDE Driver + * linux/drivers/ide/macide.c -- Macintosh IDE Driver * * Copyright (C) 1998 by Michael Schmitz * @@ -43,7 +43,7 @@ #define MAC_HD_STATUS 0x1c /* see status-bits */ #define MAC_HD_CONTROL 0x38 /* control/altstatus */ -static int macide_offsets[IDE_NR_PORTS] = { +static int __init macide_offsets[IDE_NR_PORTS] = { MAC_HD_DATA, MAC_HD_ERROR, MAC_HD_NSECTOR, MAC_HD_SECTOR, MAC_HD_LCYL, MAC_HD_HCYL, MAC_HD_SELECT, MAC_HD_STATUS, MAC_HD_CONTROL }; @@ -84,7 +84,7 @@ * Probe for a Macintosh IDE interface */ -void macide_init(void) +void __init macide_init(void) { hw_regs_t hw; int index = -1; diff -u --recursive --new-file v2.3.47/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.3.47/linux/drivers/block/md.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/block/md.c Wed Feb 23 09:13:52 2000 @@ -75,16 +75,16 @@ static struct gendisk md_gendisk= { - MD_MAJOR, - "md", - 0, - 1, - md_hd_struct, - md_size, - MAX_MD_DEVS, - NULL, - NULL, - &md_fops, + major: MD_MAJOR, + major_name: "md", + minor_shift: 0, + max_p: 1, + part: md_hd_struct, + sizes: md_size, + nr_real: MAX_MD_DEVS, + real_devices: NULL, + next: NULL, + fops: &md_fops, }; void md_plug_device (request_queue_t *mdqueue, kdev_t dev) @@ -178,17 +178,16 @@ return; } -void md_make_request (int rw, struct buffer_head * bh) +static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { - mddev_t *mddev = kdev_to_mddev(bh->b_dev); + mddev_t *mddev = kdev_to_mddev(bh->b_rdev); - if (!mddev || !mddev->pers) - bh->b_end_io(bh, 0); + if (mddev && mddev->pers) + return mddev->pers->make_request(q, mddev, rw, bh); else { - if ((rw == READ || rw == READA) && buffer_uptodate(bh)) - bh->b_end_io(bh, 1); - else - mddev->pers->make_request(mddev, rw, bh); + mark_buffer_clean(bh); + bh->b_end_io(bh, 0); + return -1; } } @@ -234,28 +233,6 @@ return mddev; } -static void free_mddev (mddev_t *mddev) -{ - if (!mddev) { - MD_BUG(); - return; - } - - /* - * Make sure nobody else is using this mddev - * (careful, we rely on the global kernel lock here) - */ - while (md_atomic_read(&mddev->resync_sem.count) != 1) - schedule(); - while (md_atomic_read(&mddev->recovery_sem.count) != 1) - schedule(); - - del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); - md_list_del(&mddev->all_mddevs); - MD_INIT_LIST_HEAD(&mddev->all_mddevs); - kfree(mddev); -} - struct gendisk * find_gendisk (kdev_t dev) { struct gendisk *tmp = gendisk_head; @@ -757,6 +734,32 @@ MD_BUG(); } +static void free_mddev (mddev_t *mddev) +{ + if (!mddev) { + MD_BUG(); + return; + } + + export_array(mddev); + md_size[mdidx(mddev)] = 0; + md_hd_struct[mdidx(mddev)].nr_sects = 0; + + /* + * Make sure nobody else is using this mddev + * (careful, we rely on the global kernel lock here) + */ + while (md_atomic_read(&mddev->resync_sem.count) != 1) + schedule(); + while (md_atomic_read(&mddev->recovery_sem.count) != 1) + schedule(); + + del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); + md_list_del(&mddev->all_mddevs); + MD_INIT_LIST_HEAD(&mddev->all_mddevs); + kfree(mddev); +} + #undef BAD_CSUM #undef BAD_MAGIC #undef OUT_OF_MEM @@ -1723,13 +1726,7 @@ printk (STILL_MOUNTED, mdidx(mddev)); OUT(-EBUSY); } - - /* - * complain if it's already stopped - */ - if (!mddev->nb_dev) - OUT(-ENXIO); - + if (mddev->pers) { /* * It is safe to call stop here, it only frees private @@ -1796,9 +1793,6 @@ * Free resources if final stop */ if (!ro) { - export_array(mddev); - md_size[mdidx(mddev)] = 0; - md_hd_struct[mdidx(mddev)].nr_sects = 0; free_mddev(mddev); printk (KERN_INFO "md%d stopped.\n", mdidx(mddev)); @@ -3279,15 +3273,15 @@ { int i; - blksize_size[MD_MAJOR] = md_blocksizes; - max_readahead[MD_MAJOR] = md_maxreadahead; - for(i = 0; i < MAX_MD_DEVS; i++) { md_blocksizes[i] = 1024; + md_size[i] = 0; md_maxreadahead[i] = MD_READAHEAD; register_disk(&md_gendisk, MKDEV(MAJOR_NR,i), 1, &md_fops, 0); - } + blksize_size[MD_MAJOR] = md_blocksizes; + blk_size[MAJOR_NR] = md_size; + max_readahead[MD_MAJOR] = md_maxreadahead; printk("md.c: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); diff -u --recursive --new-file v2.3.47/linux/drivers/block/ns87415.c linux/drivers/block/ns87415.c --- v2.3.47/linux/drivers/block/ns87415.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/ns87415.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997 + * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997 * * Copyright (C) 1997-1998 Mark Lord * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) diff -u --recursive --new-file v2.3.47/linux/drivers/block/opti621.c linux/drivers/block/opti621.c --- v2.3.47/linux/drivers/block/opti621.c Thu May 13 11:04:54 1999 +++ linux/drivers/block/opti621.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999 + * linux/drivers/block/opti621.c Version 0.6 Jan 02, 1999 * * Copyright (C) 1996-1998 Linus Torvalds & authors (see below) */ diff -u --recursive --new-file v2.3.47/linux/drivers/block/pdc202xx.c linux/drivers/block/pdc202xx.c --- v2.3.47/linux/drivers/block/pdc202xx.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/pdc202xx.c Sat Feb 26 20:32:14 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/pdc202xx.c Version 0.28 Dec. 13, 1999 + * linux/drivers/block/pdc202xx.c Version 0.29 Feb. 10, 2000 * - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * Promise Ultra33 cards with BIOS v1.20 through 1.28 will need this @@ -14,7 +14,7 @@ * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word. * The 8/4 ratio is a BIOS code limit by promise. * - * UNLESS you enable "CONFIG_PDC202XX_FORCE_BURST_BIT" + * UNLESS you enable "CONFIG_PDC202XX_BURST" * * There is only one BIOS in the three contollers. * @@ -100,6 +100,61 @@ #define PDC202XX_DEBUG_DRIVE_INFO 0 #define PDC202XX_DECODE_REGISTER_INFO 0 +#define DISPLAY_PDC202XX_TIMINGS +#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int pdc202xx_get_info(char *, char **, off_t, int); +extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static struct pci_dev *bmide_dev; + +static int pdc202xx_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + + u32 bibma = bmide_dev->resource[4].start; + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_PROMISE_20262: + p += sprintf(p, "\n PDC20262 Chipset.\n"); + break; + case PCI_DEVICE_ID_PROMISE_20246: + p += sprintf(p, "\n PDC20246 Chipset.\n"); + break; + default: + p += sprintf(p, "\n PDC202XX Chipset.\n"); + break; + } + + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; /* => must be less than 4k! */ +} +#endif /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */ + +byte pdc202xx_proc = 0; + extern char *ide_xfer_verbose (byte xfer_rate); /* A Register */ @@ -620,15 +675,15 @@ (primary_mode & 1) ? "MASTER" : "PCI", (secondary_mode & 1) ? "MASTER" : "PCI" ); -#ifdef CONFIG_PDC202XX_FORCE_BURST_BIT +#ifdef CONFIG_PDC202XX_BURST if (!(udma_speed_flag & 1)) { printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1)); outb(udma_speed_flag|1, high_16 + 0x001f); printk("%sCTIVE\n", (inb(high_16 + 0x001f) & 1) ? "A" : "INA"); } -#endif /* CONFIG_PDC202XX_FORCE_BURST_BIT */ +#endif /* CONFIG_PDC202XX_BURST */ -#ifdef CONFIG_PDC202XX_FORCE_MASTER_MODE +#ifdef CONFIG_PDC202XX_MASTER if (!(primary_mode & 1)) { printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ", name, primary_mode, (primary_mode|1)); @@ -642,7 +697,14 @@ outb(secondary_mode|1, high_16 + 0x001b); printk("%s\n", (inb(high_16 + 0x001b) & 1) ? "MASTER" : "PCI"); } -#endif /* CONFIG_PDC202XX_FORCE_MASTER_MODE */ +#endif /* CONFIG_PDC202XX_MASTER */ + +#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) + pdc202xx_proc = 1; + bmide_dev = dev; + pdc202xx_display_info = &pdc202xx_get_info; +#endif /* DISPLAY_PDC202XX_TIMINGS && CONFIG_PROC_FS */ + return dev->irq; } diff -u --recursive --new-file v2.3.47/linux/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c --- v2.3.47/linux/drivers/block/pdc4030.c Thu Nov 18 20:25:37 1999 +++ linux/drivers/block/pdc4030.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* -*- linux-c -*- - * linux/drivers/block/pdc4030.c Version 0.90 May 27, 1999 + * linux/drivers/ide/pdc4030.c Version 0.90 May 27, 1999 * * Copyright (C) 1995-1999 Linus Torvalds & authors (see below) */ diff -u --recursive --new-file v2.3.47/linux/drivers/block/pdc4030.h linux/drivers/block/pdc4030.h --- v2.3.47/linux/drivers/block/pdc4030.h Sun Nov 30 13:48:47 1997 +++ linux/drivers/block/pdc4030.h Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/pdc4030.h + * linux/drivers/ide/pdc4030.h * * Copyright (C) 1995-1998 Linus Torvalds & authors */ diff -u --recursive --new-file v2.3.47/linux/drivers/block/piix.c linux/drivers/block/piix.c --- v2.3.47/linux/drivers/block/piix.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/piix.c Sat Feb 26 20:32:14 2000 @@ -1,8 +1,8 @@ /* - * linux/drivers/block/piix.c Version 0.28 Dec. 13, 1999 + * linux/drivers/block/piix.c Version 0.30 Feb. 26, 2000 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer - * Copyright (C) 1998-1999 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * PIO mode setting function for Intel chipsets. @@ -49,13 +49,33 @@ * pci_read_config_word(HWIF(drive)->pci_dev, 0x44, ®44); * pci_read_config_word(HWIF(drive)->pci_dev, 0x48, ®48); * pci_read_config_word(HWIF(drive)->pci_dev, 0x4a, ®4a); + * pci_read_config_word(HWIF(drive)->pci_dev, 0x54, ®54); + * + * 00:1f.1 IDE interface: Intel Corporation: + * Unknown device 2411 (rev 01) (prog-if 80 [Master]) + * Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- + * ParErr- Stepping- SERR- FastB2B- + * Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- + * SERR- @@ -86,16 +106,88 @@ static int piix_get_info (char *buffer, char **addr, off_t offset, int count) { - /* int rc; */ - int piix_who = ((bmide_dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || - (bmide_dev->device == PCI_DEVICE_ID_INTEL_82801AB_1) || - (bmide_dev->device == PCI_DEVICE_ID_INTEL_82371AB)) ? 4 : 3; char *p = buffer; - p += sprintf(p, "\n Intel PIIX%d Chipset.\n", piix_who); - p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n\n"); + u32 bibma = bmide_dev->resource[4].start; + u16 reg40 = 0, psitre = 0, reg42 = 0, ssitre = 0; + u8 c0 = 0, c1 = 0; + u8 reg44 = 0, reg48 = 0, reg4a = 0, reg4b = 0, reg54 = 0; + + pci_read_config_word(bmide_dev, 0x40, ®40); + pci_read_config_word(bmide_dev, 0x42, ®42); + pci_read_config_byte(bmide_dev, 0x44, ®44); + pci_read_config_byte(bmide_dev, 0x48, ®48); + pci_read_config_byte(bmide_dev, 0x4a, ®4a); + pci_read_config_byte(bmide_dev, 0x4b, ®4b); + pci_read_config_byte(bmide_dev, 0x54, ®54); + + psitre = (reg40 & 0x4000) ? 1 : 0; + ssitre = (reg42 & 0x4000) ? 1 : 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + switch(bmide_dev->device) { + case PCI_DEVICE_ID_INTEL_82372FB_1: + case PCI_DEVICE_ID_INTEL_82801AA_1: + p += sprintf(p, "\n Intel PIIX4 Ultra 66 Chipset.\n"); + break; + case PCI_DEVICE_ID_INTEL_82801AB_1: + case PCI_DEVICE_ID_INTEL_82371AB: + p += sprintf(p, "\n Intel PIIX4 Ultra 33 Chipset.\n"); + break; + case PCI_DEVICE_ID_INTEL_82371SB_1: + p += sprintf(p, "\n Intel PIIX3 Chipset.\n"); + break; + case PCI_DEVICE_ID_INTEL_82371FB_1: + case PCI_DEVICE_ID_INTEL_82371FB_0: + default: + p += sprintf(p, "\n Intel PIIX Chipset.\n"); + break; + } + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); - p += sprintf(p, "\n"); - p += sprintf(p, "\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", + (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", + (c1&0x40) ? "yes" : "no " ); + p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + (reg48&0x01) ? "yes" : "no ", + (reg48&0x02) ? "yes" : "no ", + (reg48&0x04) ? "yes" : "no ", + (reg48&0x08) ? "yes" : "no " ); + p += sprintf(p, "UDMA enabled: %s %s %s %s\n", + ((reg54&0x11) && (reg4a&0x02)) ? "4" : + ((reg54&0x11) && (reg4a&0x01)) ? "3" : + (reg4a&0x02) ? "2" : + (reg4a&0x01) ? "1" : + (reg4a&0x00) ? "0" : "X", + ((reg54&0x22) && (reg4a&0x20)) ? "4" : + ((reg54&0x22) && (reg4a&0x10)) ? "3" : + (reg4a&0x20) ? "2" : + (reg4a&0x10) ? "1" : + (reg4a&0x00) ? "0" : "X", + ((reg54&0x44) && (reg4b&0x02)) ? "4" : + ((reg54&0x44) && (reg4b&0x01)) ? "3" : + (reg4b&0x02) ? "2" : + (reg4b&0x01) ? "1" : + (reg4b&0x00) ? "0" : "X", + ((reg54&0x88) && (reg4b&0x20)) ? "4" : + ((reg54&0x88) && (reg4b&0x10)) ? "3" : + (reg4b&0x20) ? "2" : + (reg4b&0x10) ? "1" : + (reg4b&0x00) ? "0" : "X"); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); /* * FIXME.... Add configuration junk data....blah blah...... @@ -113,7 +205,6 @@ extern char *ide_xfer_verbose (byte xfer_rate); -#ifdef CONFIG_BLK_DEV_PIIX_TUNING /* * */ @@ -143,7 +234,6 @@ return 0; } } -#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ /* * Based on settings done by AMI BIOS @@ -191,8 +281,6 @@ restore_flags(flags); } -#ifdef CONFIG_BLK_DEV_PIIX_TUNING - static int piix_config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -205,12 +293,15 @@ byte maslave = hwif->channel ? 0x42 : 0x40; byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; - int ultra = ((dev->device == PCI_DEVICE_ID_INTEL_82371AB) || + int ultra66 = ((dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) || + (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0; + int ultra = ((ultra66) || + (dev->device == PCI_DEVICE_ID_INTEL_82371AB) || (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0; - int ultra66 = (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ? 1 : 0; int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); int a_speed = 2 << (drive_number * 4); int u_flag = 1 << drive_number; + int v_flag = 0x10 << drive_number; int u_speed = 0; pci_read_config_word(dev, maslave, ®4042); @@ -245,10 +336,6 @@ speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL); } - /* - * This is !@#$% ugly and stupid............. - * But ugly harware generates ugly code......... - */ if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) pci_write_config_word(dev, 0x48, reg48|u_flag); @@ -256,10 +343,12 @@ pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); pci_write_config_word(dev, 0x4a, reg4a|u_speed); } - if ((speed > XFER_UDMA_2) && (!(reg54 & u_flag))) { - pci_write_config_word(dev, 0x54, reg54|u_flag); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) { + pci_write_config_word(dev, 0x54, reg54|v_flag); + } } else { - pci_write_config_word(dev, 0x54, reg54 & ~u_flag); + pci_write_config_word(dev, 0x54, reg54 & ~v_flag); } } @@ -268,8 +357,8 @@ pci_write_config_word(dev, 0x48, reg48 & ~u_flag); if (reg4a & a_speed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - if (reg54 & u_flag) - pci_write_config_word(dev, 0x54, reg54 & ~u_flag); + if (reg54 & v_flag) + pci_write_config_word(dev, 0x54, reg54 & ~v_flag); } piix_tune_drive(drive, piix_dma_2_pio(speed)); @@ -277,8 +366,7 @@ (void) ide_config_drive_speed(drive, speed); #if PIIX_DEBUG_DRIVE_INFO - printk("%s: %s drive%d ", drive->name, ide_xfer_verbose(speed), drive_number); - printk("\n"); + printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive_number); #endif /* PIIX_DEBUG_DRIVE_INFO */ return ((int) ((id->dma_ultra >> 11) & 3) ? ide_dma_on : @@ -299,16 +387,13 @@ /* Other cases are done by generic IDE-DMA code. */ return ide_dmaproc(func, drive); } -#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name) { #if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS) - if (!piix_proc) { - piix_proc = 1; - bmide_dev = dev; - piix_display_info = &piix_get_info; - } + piix_proc = 1; + bmide_dev = dev; + piix_display_info = &piix_get_info; #endif /* DISPLAY_PIIX_TIMINGS && CONFIG_PROC_FS */ return 0; } @@ -325,7 +410,7 @@ pci_read_config_byte(hwif->pci_dev, 0x54, ®54h); pci_read_config_byte(hwif->pci_dev, 0x55, ®55h); - ata66 = (reg54h & mask) ? 0 : 1; + ata66 = (reg54h & mask) ? 1 : 0; return ata66; } @@ -335,9 +420,9 @@ hwif->tuneproc = &piix_tune_drive; if (hwif->dma_base) { -#ifdef CONFIG_BLK_DEV_PIIX_TUNING +#ifdef CONFIG_PIIX_TUNING hwif->dmaproc = &piix_dmaproc; -#endif /* CONFIG_BLK_DEV_PIIX_TUNING */ +#endif /* CONFIG_PIIX_TUNING */ hwif->drives[0].autotune = 0; hwif->drives[1].autotune = 0; } else { diff -u --recursive --new-file v2.3.47/linux/drivers/block/qd6580.c linux/drivers/block/qd6580.c --- v2.3.47/linux/drivers/block/qd6580.c Thu May 13 11:04:54 1999 +++ linux/drivers/block/qd6580.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996 + * linux/drivers/block/qd6580.c Version 0.02 Feb 09, 1996 * * Copyright (C) 1996 Linus Torvalds & author (see below) */ @@ -60,7 +60,7 @@ restore_flags(flags); /* all CPUs */ } -void init_qd6580 (void) +void __init init_qd6580 (void) { ide_hwifs[0].chipset = ide_qd6580; ide_hwifs[1].chipset = ide_qd6580; diff -u --recursive --new-file v2.3.47/linux/drivers/block/raid0.c linux/drivers/block/raid0.c --- v2.3.47/linux/drivers/block/raid0.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/block/raid0.c Wed Feb 23 09:13:52 2000 @@ -223,23 +223,23 @@ * Of course, those facts may not be valid anymore (and surely won't...) * Hey guys, there's some work out there ;-) */ -static int raid0_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) +static int raid0_make_request (request_queue_t *q, mddev_t *mddev, + int rw, struct buffer_head * bh) { - unsigned long size = bh->b_size >> 10; + int blk_in_chunk, chunksize_bits, chunk, chunk_size; raid0_conf_t *conf = mddev_to_conf(mddev); struct raid0_hash *hash; struct strip_zone *zone; mdk_rdev_t *tmp_dev; - int blk_in_chunk, chunksize_bits, chunk, chunk_size; long block, rblock; chunk_size = mddev->param.chunk_size >> 10; chunksize_bits = ffz(~chunk_size); - block = bh->b_blocknr * size; + block = bh->b_rsector >> 1; hash = conf->hash_table + block / conf->smallest->size; /* Sanity check */ - if (chunk_size < (block % chunk_size) + size) + if (chunk_size < (block % chunk_size) + (bh->b_size >> 10)) goto bad_map; if (!hash) @@ -261,20 +261,19 @@ rblock = (chunk << chunksize_bits) + blk_in_chunk + zone->dev_offset; /* - * Important, at this point we are not guaranteed to be the only - * CPU modifying b_rdev and b_rsector! Only __make_request() later - * on serializes the IO. So in 2.4 we must never write temporary - * values to bh->b_rdev, like 2.2 and 2.0 did. + * The new BH_Lock semantics in ll_rw_blk.c guarantee that this + * is the only IO operation happening on this bh. */ bh->b_rdev = tmp_dev->dev; bh->b_rsector = rblock << 1; - generic_make_request(rw, bh); - - return 0; + /* + * Let the main block layer submit the IO and resolve recursion: + */ + return 1; bad_map: - printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %ld\n", chunk_size, bh->b_rsector, size); + printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %d\n", chunk_size, bh->b_rsector, bh->b_size >> 10); return -1; bad_hash: printk("raid0_make_request bug: hash==NULL for block %ld\n", block); diff -u --recursive --new-file v2.3.47/linux/drivers/block/rapide.c linux/drivers/block/rapide.c --- v2.3.47/linux/drivers/block/rapide.c Thu Jun 17 01:11:35 1999 +++ linux/drivers/block/rapide.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * linux/arch/arm/drivers/block/ide-rapide.c + * linux/drivers/block/rapide.c * * Copyright (c) 1996-1998 Russell King. * @@ -16,7 +16,7 @@ #include -static const card_ids rapide_cids[] = { +static const card_ids __init rapide_cids[] = { { MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 }, { 0xffff, 0xffff } }; @@ -43,7 +43,7 @@ return ide_register_hw(&hw, NULL); } -int rapide_init(void) +int __init rapide_init(void) { int i; diff -u --recursive --new-file v2.3.47/linux/drivers/block/rz1000.c linux/drivers/block/rz1000.c --- v2.3.47/linux/drivers/block/rz1000.c Mon Oct 4 15:49:29 1999 +++ linux/drivers/block/rz1000.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997 + * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997 * * Copyright (C) 1995-1998 Linus Torvalds & author (see below) */ diff -u --recursive --new-file v2.3.47/linux/drivers/block/sis5513.c linux/drivers/block/sis5513.c --- v2.3.47/linux/drivers/block/sis5513.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/sis5513.c Sat Feb 26 20:32:14 2000 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/sis5513.c Version 0.08 Dec. 13, 1999 + * linux/drivers/block/sis5513.c Version 0.09 Feb. 10, 2000 * - * Copyright (C) 1999 Andre Hedrick (andre@suse.com) + * Copyright (C) 1999-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * Thanks to SIS Taiwan for direct support and hardware. @@ -50,6 +50,7 @@ { "SiS540", PCI_DEVICE_ID_SI_540, SIS5513_FLAG_ATA_66, }, { "SiS620", PCI_DEVICE_ID_SI_620, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, { "SiS630", PCI_DEVICE_ID_SI_630, SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, }, + { "SiS5591", PCI_DEVICE_ID_SI_5591, SIS5513_FLAG_ATA_33, }, { "SiS5597", PCI_DEVICE_ID_SI_5597, SIS5513_FLAG_ATA_33, }, { "SiS5600", PCI_DEVICE_ID_SI_5600, SIS5513_FLAG_ATA_33, }, { "SiS5511", PCI_DEVICE_ID_SI_5511, SIS5513_FLAG_ATA_16, }, @@ -233,8 +234,10 @@ byte drive_pci, test1, test2, mask; int err; + unsigned long dma_base = hwif->dma_base; + byte unit = (drive->select.b.unit & 0x01); byte speed = 0x00, unmask = 0xE0, four_two = 0x00; - int drive_number = ((hwif->channel ? 2 : 0) + (drive->select.b.unit & 0x01)); + int drive_number = ((hwif->channel ? 2 : 0) + unit); byte udma_66 = ((id->hw_config & 0x2000) && (hwif->udma_four)) ? 1 : 0; if (host_dev) { @@ -314,6 +317,7 @@ return ((int) ide_dma_off_quietly); } + outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2); err = ide_config_drive_speed(drive, speed); #if SIS5513_DEBUG_DRIVE_INFO @@ -532,6 +536,7 @@ case PCI_DEVICE_ID_SI_630: case PCI_DEVICE_ID_SI_5600: case PCI_DEVICE_ID_SI_5597: + case PCI_DEVICE_ID_SI_5591: hwif->autodma = 1; hwif->dmaproc = &sis5513_dmaproc; break; diff -u --recursive --new-file v2.3.47/linux/drivers/block/sl82c105.c linux/drivers/block/sl82c105.c --- v2.3.47/linux/drivers/block/sl82c105.c Mon Dec 20 18:48:21 1999 +++ linux/drivers/block/sl82c105.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * drivers/block/sl82c105.c + * linux/drivers/block/sl82c105.c * * SL82C105/Winbond 553 IDE driver * diff -u --recursive --new-file v2.3.47/linux/drivers/block/trm290.c linux/drivers/block/trm290.c --- v2.3.47/linux/drivers/block/trm290.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/trm290.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/trm290.c Version 1.01 December 5, 1997 + * linux/drivers/block/trm290.c Version 1.01 December 5, 1997 * * Copyright (c) 1997-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License diff -u --recursive --new-file v2.3.47/linux/drivers/block/umc8672.c linux/drivers/block/umc8672.c --- v2.3.47/linux/drivers/block/umc8672.c Thu May 13 11:04:54 1999 +++ linux/drivers/block/umc8672.c Sat Feb 26 20:32:14 2000 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996 + * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & author (see below) */ @@ -76,7 +76,7 @@ outb_p (wert,0x109); } -static byte in_umc (char port) +static inline byte in_umc (char port) { outb_p (port,0x108); return inb_p (0x109); @@ -125,7 +125,7 @@ restore_flags(flags); /* all CPUs */ } -void init_umc8672 (void) /* called from ide.c */ +void __init init_umc8672 (void) /* called from ide.c */ { unsigned long flags; diff -u --recursive --new-file v2.3.47/linux/drivers/block/via82cxxx.c linux/drivers/block/via82cxxx.c --- v2.3.47/linux/drivers/block/via82cxxx.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/block/via82cxxx.c Sat Feb 26 20:32:14 2000 @@ -1,9 +1,10 @@ /* - * linux/drivers/block/via82cxxx.c Version 0.06 Dec. 13, 1999 + * linux/drivers/block/via82cxxx.c Version 0.07 Feb. 10, 2000 * - * Copyright (C) 1998-99 Michel Aubry, Maintainer - * Copyright (C) 1999 Jeff Garzik, MVP4 Support (jgarzik@mandrakesoft.com) - * Copyright (C) 1998-99 Andre Hedrick (andre@suse.com) + * Copyright (C) 1998-99 Michel Aubry, Maintainer + * Copyright (C) 1999 Jeff Garzik, MVP4 Support + * (jgarzik@mandrakesoft.com) + * Copyright (C) 1998-2000 Andre Hedrick (andre@suse.com) * May be copied or modified under the terms of the GNU General Public License * * The VIA MVP-4 is reported OK with UDMA. @@ -473,12 +474,6 @@ !(newfifo & 0x03) ? "1" : (!(newfifo & 0x02) ? "3/4" : (newfifo & 0x01) ? "1/4" : "1/2")); - -#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) - via_proc = 1; - bmide_dev = hwif->pci_dev; - via_display_info = &via_get_info; -#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ return 0; } @@ -530,6 +525,12 @@ printk("\n"); } +#if defined(DISPLAY_VIA_TIMINGS) && defined(CONFIG_PROC_FS) + via_proc = 1; + bmide_dev = dev; + via_display_info = &via_get_info; +#endif /* DISPLAY_VIA_TIMINGS && CONFIG_PROC_FS*/ + return 0; } @@ -555,7 +556,7 @@ } /* - * ide_dmacapable_via82c568(ide_hwif_t *, unsigned long) + * ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long) * checks if channel "channel" of if hwif is dma * capable or not, according to kernel command line, * and the new fifo settings. diff -u --recursive --new-file v2.3.47/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.3.47/linux/drivers/char/Config.in Wed Feb 16 17:03:51 2000 +++ linux/drivers/char/Config.in Sat Feb 26 20:23:28 2000 @@ -122,7 +122,8 @@ tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC -if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then +bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC +if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then bool 'Tadpole ANA H8 Support' CONFIG_H8 fi diff -u --recursive --new-file v2.3.47/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.3.47/linux/drivers/char/Makefile Sun Feb 20 21:12:38 2000 +++ linux/drivers/char/Makefile Sat Feb 26 20:23:31 2000 @@ -61,6 +61,16 @@ SERIAL = endif +ifeq ($(CONFIG_DECSTATION),y) + KEYBD = + SERIAL = +endif + +ifeq ($(CONFIG_BAGET_MIPS),y) + KEYBD = + SERIAL = +endif + ifneq ($(CONFIG_SUN_SERIAL),) SERIAL = endif @@ -148,13 +158,17 @@ obj-$(CONFIG_PC110_PAD) += pc110pad.o obj-$(CONFIG_WDT) += wdt.o obj-$(CONFIG_RTC) += rtc.o +obj-$(CONFIG_EFI_RTC) += efirtc.o ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif -obj-$(CONFIG_I810_RNG) += i810_rng.o obj-$(CONFIG_VIDEO_DEV) += videodev.o +obj-$(CONFIG_21825_WATCHDOG) += wdt285.o +obj-$(CONFIG_977_WATCHDOG) += wdt977.o +obj-$(CONFIG_DS1620) += ds1620.o + # # for external dependencies in arm/config.in and video/config.in # @@ -195,7 +209,7 @@ L_I2C = y else ifeq ($(CONFIG_I2C_PARPORT),m) - M_I2C = y + L_I2C = m endif endif @@ -262,6 +276,13 @@ # set when a framegrabber implements i2c support obj-$(L_I2C) += i2c-old.o + +ifeq ($(CONFIG_DZ),y) + L_OBJS += dz.o +endif + +obj-$(CONFIG_NWBUTTON) += nwbutton.o +obj-$(CONFIG_NWFLASH) += nwflash.o ifeq ($(CONFIG_DRM),y) SUB_DIRS += drm diff -u --recursive --new-file v2.3.47/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c --- v2.3.47/linux/drivers/char/agp/agpgart_be.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/char/agp/agpgart_be.c Mon Feb 21 11:19:00 2000 @@ -1397,8 +1397,6 @@ agp_bridge.free_by_type = agp_generic_free_by_type; return 0; - - (void) pdev; /* unused */ } #endif /* CONFIG_AGP_SIS */ diff -u --recursive --new-file v2.3.47/linux/drivers/char/ds1620.c linux/drivers/char/ds1620.c --- v2.3.47/linux/drivers/char/ds1620.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/ds1620.c Thu Feb 24 22:56:47 2000 @@ -0,0 +1,436 @@ +/* + * linux/drivers/char/ds1620.c: Dallas Semiconductors DS1620 + * thermometer driver (as used in the Rebel.com NetWinder) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_PROC_FS +/* define for /proc interface */ +#define THERM_USE_PROC +#endif + +/* Definitions for DS1620 chip */ +#define THERM_START_CONVERT 0xee +#define THERM_RESET 0xaf +#define THERM_READ_CONFIG 0xac +#define THERM_READ_TEMP 0xaa +#define THERM_READ_TL 0xa2 +#define THERM_READ_TH 0xa1 +#define THERM_WRITE_CONFIG 0x0c +#define THERM_WRITE_TL 0x02 +#define THERM_WRITE_TH 0x01 + +#define CFG_CPU 2 +#define CFG_1SHOT 1 + +static const char *fan_state[] = { "off", "on", "on (hardwired)" }; + +/* + * Start of NetWinder specifics + * Note! We have to hold the gpio lock with IRQs disabled over the + * whole of our transaction to the Dallas chip, since there is a + * chance that the WaveArtist driver could touch these bits to + * enable or disable the speaker. + */ +extern spinlock_t gpio_lock; +extern unsigned int system_rev; + +static inline void netwinder_ds1620_set_clk(int clk) +{ + gpio_modify_op(GPIO_DSCLK, clk ? GPIO_DSCLK : 0); +} + +static inline void netwinder_ds1620_set_data(int dat) +{ + gpio_modify_op(GPIO_DATA, dat ? GPIO_DATA : 0); +} + +static inline int netwinder_ds1620_get_data(void) +{ + return gpio_read() & GPIO_DATA; +} + +static inline void netwinder_ds1620_set_data_dir(int dir) +{ + gpio_modify_io(GPIO_DATA, dir ? GPIO_DATA : 0); +} + +static inline void netwinder_ds1620_reset(void) +{ + cpld_modify(CPLD_DS_ENABLE, 0); + cpld_modify(CPLD_DS_ENABLE, CPLD_DS_ENABLE); +} + +static inline void netwinder_lock(unsigned long *flags) +{ + spin_lock_irqsave(&gpio_lock, *flags); +} + +static inline void netwinder_unlock(unsigned long *flags) +{ + spin_unlock_irqrestore(&gpio_lock, *flags); +} + +static inline void netwinder_set_fan(int i) +{ + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0); + spin_unlock_irqrestore(&gpio_lock, flags); +} + +static inline int netwinder_get_fan(void) +{ + if ((system_rev & 0xf000) == 0x4000) + return FAN_ALWAYS_ON; + + return (gpio_read() & GPIO_FAN) ? FAN_ON : FAN_OFF; +} + +/* + * End of NetWinder specifics + */ + +static void ds1620_send_bits(int nr, int value) +{ + int i; + + for (i = 0; i < nr; i++) { + netwinder_ds1620_set_data(value & 1); + netwinder_ds1620_set_clk(0); + udelay(1); + netwinder_ds1620_set_clk(1); + udelay(1); + + value >>= 1; + } +} + +static unsigned int ds1620_recv_bits(int nr) +{ + unsigned int value = 0, mask = 1; + int i; + + netwinder_ds1620_set_data(0); + + for (i = 0; i < nr; i++) { + netwinder_ds1620_set_clk(0); + udelay(1); + + if (netwinder_ds1620_get_data()) + value |= mask; + + mask <<= 1; + + netwinder_ds1620_set_clk(1); + udelay(1); + } + + return value; +} + +static void ds1620_out(int cmd, int bits, int value) +{ + unsigned long flags; + + netwinder_lock(&flags); + netwinder_ds1620_set_clk(1); + netwinder_ds1620_set_data_dir(0); + netwinder_ds1620_reset(); + + udelay(1); + + ds1620_send_bits(8, cmd); + if (bits) + ds1620_send_bits(bits, value); + + udelay(1); + + netwinder_ds1620_reset(); + netwinder_unlock(&flags); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2); +} + +static unsigned int ds1620_in(int cmd, int bits) +{ + unsigned long flags; + unsigned int value; + + netwinder_lock(&flags); + netwinder_ds1620_set_clk(1); + netwinder_ds1620_set_data_dir(0); + netwinder_ds1620_reset(); + + udelay(1); + + ds1620_send_bits(8, cmd); + + netwinder_ds1620_set_data_dir(1); + value = ds1620_recv_bits(bits); + + netwinder_ds1620_reset(); + netwinder_unlock(&flags); + + return value; +} + +static int cvt_9_to_int(unsigned int val) +{ + if (val & 0x100) + val |= 0xfffffe00; + + return val; +} + +static void ds1620_write_state(struct therm *therm) +{ + ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU); + ds1620_out(THERM_WRITE_TL, 9, therm->lo); + ds1620_out(THERM_WRITE_TH, 9, therm->hi); + ds1620_out(THERM_START_CONVERT, 0, 0); +} + +static void ds1620_read_state(struct therm *therm) +{ + therm->lo = cvt_9_to_int(ds1620_in(THERM_READ_TL, 9)); + therm->hi = cvt_9_to_int(ds1620_in(THERM_READ_TH, 9)); +} + +static ssize_t +ds1620_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + signed int cur_temp; + signed char cur_temp_degF; + + /* Can't seek (pread) on this device */ + if (ptr != &file->f_pos) + return -ESPIPE; + + cur_temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)) >> 1; + + /* convert to Fahrenheit, as per wdt.c */ + cur_temp_degF = (cur_temp * 9) / 5 + 32; + + if (copy_to_user(buf, &cur_temp_degF, 1)) + return -EFAULT; + + return 1; +} + +static int +ds1620_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct therm therm; + int i; + + switch(cmd) { + case CMD_SET_THERMOSTATE: + case CMD_SET_THERMOSTATE2: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (cmd == CMD_SET_THERMOSTATE) { + if (get_user(therm.hi, (int *)arg)) + return -EFAULT; + therm.lo = therm.hi - 3; + } else { + if (copy_from_user(&therm, (void *)arg, sizeof(therm))) + return -EFAULT; + } + + therm.lo <<= 1; + therm.hi <<= 1; + + ds1620_write_state(&therm); + break; + + case CMD_GET_THERMOSTATE: + case CMD_GET_THERMOSTATE2: + ds1620_read_state(&therm); + + therm.lo >>= 1; + therm.hi >>= 1; + + if (cmd == CMD_GET_THERMOSTATE) { + if (put_user(therm.hi, (int *)arg)) + return -EFAULT; + } else { + if (copy_to_user((void *)arg, &therm, sizeof(therm))) + return -EFAULT; + } + break; + + case CMD_GET_TEMPERATURE: + case CMD_GET_TEMPERATURE2: + i = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); + + if (cmd == CMD_GET_TEMPERATURE) + i >>= 1; + + return put_user(i, (int *)arg) ? -EFAULT : 0; + + case CMD_GET_STATUS: + i = ds1620_in(THERM_READ_CONFIG, 8) & 0xe3; + + return put_user(i, (int *)arg) ? -EFAULT : 0; + + case CMD_GET_FAN: + i = netwinder_get_fan(); + + return put_user(i, (int *)arg) ? -EFAULT : 0; + + case CMD_SET_FAN: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (get_user(i, (int *)arg)) + return -EFAULT; + + netwinder_set_fan(i); + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static int +ds1620_open(struct inode *inode, struct file *file) +{ + MOD_INC_USE_COUNT; + + return 0; +} + +static int +ds1620_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + + return 0; +} + +#ifdef THERM_USE_PROC +static int +proc_therm_ds1620_read(char *buf, char **start, off_t offset, + int len, int *eof, void *unused) +{ + struct therm th; + int temp; + + ds1620_read_state(&th); + temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); + + len = sprintf(buf, "Thermostat: HI %i.%i, LOW %i.%i; " + "temperature: %i.%i C, fan %s\n", + th.hi >> 1, th.hi & 1 ? 5 : 0, + th.lo >> 1, th.lo & 1 ? 5 : 0, + temp >> 1, temp & 1 ? 5 : 0, + fan_state[netwinder_get_fan()]); + + return len; +} + +static struct proc_dir_entry *proc_therm_ds1620; +#endif + +static struct file_operations ds1620_fops = { + NULL, /* lseek */ + ds1620_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + ds1620_ioctl, /* ioctl */ + NULL, /* mmap */ + ds1620_open, /* open */ + NULL, /* flush */ + ds1620_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ +}; + +static struct miscdevice ds1620_miscdev = { + TEMP_MINOR, + "temp", + &ds1620_fops +}; + +int __init ds1620_init(void) +{ + int ret; + struct therm th, th_start; + + if (!machine_is_netwinder()) + return -ENODEV; + + ds1620_out(THERM_RESET, 0, 0); + ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU); + ds1620_out(THERM_START_CONVERT, 0, 0); + + /* + * Trigger the fan to start by setting + * temperature high point low. This kicks + * the fan into action. + */ + ds1620_read_state(&th); + th_start.lo = 0; + th_start.hi = 1; + ds1620_write_state(&th_start); + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2*HZ); + + ds1620_write_state(&th); + + ret = misc_register(&ds1620_miscdev); + if (ret < 0) + return ret; + +#ifdef THERM_USE_PROC + proc_therm_ds1620 = create_proc_entry("therm", 0, 0); + if (proc_therm_ds1620) + proc_therm_ds1620->read_proc = proc_therm_ds1620_read; + else + printk(KERN_ERR "therm: unable to register /proc/therm\n"); +#endif + + ds1620_read_state(&th); + ret = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); + + printk(KERN_INFO "Thermostat: high %i.%i, low %i.%i, " + "current %i.%i C, fan %s.\n", + th.hi >> 1, th.hi & 1 ? 5 : 0, + th.lo >> 1, th.lo & 1 ? 5 : 0, + ret >> 1, ret & 1 ? 5 : 0, + fan_state[netwinder_get_fan()]); + + return 0; +} + +void __exit ds1620_exit(void) +{ +#ifdef THERM_USE_PROC + remove_proc_entry("therm", NULL); +#endif + misc_deregister(&ds1620_miscdev); +} + +module_init(ds1620_init); +module_exit(ds1620_exit); diff -u --recursive --new-file v2.3.47/linux/drivers/char/dz.c linux/drivers/char/dz.c --- v2.3.47/linux/drivers/char/dz.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/char/dz.c Fri Feb 25 10:26:42 2000 @@ -14,6 +14,9 @@ * 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 + * + * Parts (C) 1999 David Airlie, airlied@linux.ie + * [07-SEP-99] Bugfixes */ #define DEBUG_DZ 1 @@ -26,7 +29,6 @@ #define MOD_DEC_USE_COUNT #endif -#include #include #include #include @@ -74,7 +76,7 @@ DECLARE_TASK_QUEUE(tq_serial); -extern struct wait_queue *keypress_wait; +extern wait_queue_head_t keypress_wait; static struct dz_serial *lines[4]; static unsigned char tmp_buffer[256]; @@ -131,9 +133,13 @@ static void dz_stop (struct tty_struct *tty) { - struct dz_serial *info = (struct dz_serial *)tty->driver_data; + struct dz_serial *info; unsigned short mask, tmp; + 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 */ @@ -1040,7 +1046,7 @@ } if (--info->count < 0) { - printk("rs_close: bad serial port count for ttys%d: %d\n", + printk("ds_close: bad serial port count for ttys%d: %d\n", info->line, info->count); info->count = 0; } @@ -1127,7 +1133,7 @@ */ static int block_til_ready (struct tty_struct *tty, struct file *filp, struct dz_serial *info) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; @@ -1339,9 +1345,9 @@ panic("Couldn't register callout driver\n"); save_flags(flags); cli(); - i = 0; - for (info = &multi[i]; i < DZ_NB_PORT; i++) + for (i=0; i < DZ_NB_PORT; i++) { + info = &multi[i]; lines[i] = info; info->magic = SERIAL_MAGIC; @@ -1364,8 +1370,8 @@ info->tqueue_hangup.data = info; info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; - info->open_wait = 0; - info->close_wait = 0; + 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. */ @@ -1400,7 +1406,7 @@ #ifdef CONFIG_SERIAL_CONSOLE static void dz_console_put_char (unsigned char ch) { - long flags; + unsigned long flags; int loops = 2500; unsigned short tmp = ch; /* this code sends stuff out to serial device - spinning its @@ -1414,7 +1420,7 @@ /* spin our wheels */ - while (((dz_in(dz_console,DZ_TCR) & DZ_TRDY) != DZ_TRDY) && loops--) + while (((dz_in(dz_console,DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--) ; /* Actually transmit the character. */ @@ -1533,38 +1539,6 @@ dz_console->cflags |= DZ_CS8; dz_console->cflags |= DZ_PARENB; 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 */ - if (!(tmp & mask)) { - tmp |= mask; /* set the TX flag */ - dz_out (dz_console, DZ_TCR, tmp); - } - - - /* TOFIX: force to console line */ - dz_console = &multi[CONSOLE_LINE]; - if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) - dz_console->port = KN01_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) - ; - - /* enable scanning */ - dz_out(dz_console, DZ_CSR, DZ_MSE); - - /* Set up flags... */ - dz_console->cflags = 0; - dz_console->cflags |= DZ_B9600; - dz_console->cflags |= DZ_CS8; - dz_console->cflags |= DZ_PARENB; - 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 */ diff -u --recursive --new-file v2.3.47/linux/drivers/char/dz.h linux/drivers/char/dz.h --- v2.3.47/linux/drivers/char/dz.h Fri Jun 25 17:39:14 1999 +++ linux/drivers/char/dz.h Fri Feb 25 10:26:42 2000 @@ -158,8 +158,8 @@ struct tq_struct tqueue_hangup; struct termios normal_termios; struct termios callout_termios; - struct wait_queue *open_wait; - struct wait_queue *close_wait; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; long session; /* Session of opening process */ long pgrp; /* pgrp of opening process */ @@ -188,7 +188,7 @@ * memory if large numbers of serial ports are open. */ static unsigned char *tmp_buf; -static struct semaphore tmp_buf_sem = MUTEX; +static DECLARE_MUTEX(tmp_buf_sem); static char *dz_name = "DECstation DZ serial driver version "; static char *dz_version = "1.02"; diff -u --recursive --new-file v2.3.47/linux/drivers/char/efirtc.c linux/drivers/char/efirtc.c --- v2.3.47/linux/drivers/char/efirtc.c Thu Feb 10 17:11:07 2000 +++ linux/drivers/char/efirtc.c Thu Feb 24 10:14:29 2000 @@ -334,6 +334,7 @@ if (len<0) len = 0; return len; } + static int __init efi_rtc_init(void) { @@ -345,6 +346,7 @@ return 0; } + static int __exit efi_rtc_exit(void) { diff -u --recursive --new-file v2.3.47/linux/drivers/char/h8.c linux/drivers/char/h8.c --- v2.3.47/linux/drivers/char/h8.c Sun Feb 20 21:12:38 2000 +++ linux/drivers/char/h8.c Thu Feb 24 09:13:46 2000 @@ -6,6 +6,8 @@ * * Fixes: * June 1999, AV added releasing /proc/driver/h8 + * Feb 2000, Borislav Deianov + * changed queues to use list.h instead of lists.h */ #include @@ -23,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -52,18 +54,13 @@ /* * Forward declarations. */ -int h8_init(void); +static int h8_init(void); int h8_display_blank(void); int h8_display_unblank(void); static void h8_intr(int irq, void *dev_id, struct pt_regs *regs); -#ifdef CONFIG_PROC_FS static int h8_get_info(char *, char **, off_t, int); -#else -static int h8_get_info(char *, char **, off_t, int) {} -#error "Somebody needs to learn C. Badly." -#endif /* * Support Routines. @@ -141,7 +138,9 @@ unsigned int h8_index = -1; unsigned int h8_enabled = 0; -queue_head_t h8_actq, h8_cmdq, h8_freeq; +LIST_HEAD(h8_actq); +LIST_HEAD(h8_cmdq); +LIST_HEAD(h8_freeq); /* * Globals used in thermal control of Alphabook1. @@ -170,7 +169,7 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) { u_char stat_reg, data_reg; - h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link); + h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link); stat_reg = H8_GET_STATUS; data_reg = H8_READ_DATA; @@ -260,7 +259,7 @@ return; } else if (data_reg == H8_SYNC_BYTE) { h8_state = H8_IDLE; - if (!QUEUE_IS_EMPTY(&h8_actq, link)) + if (!list_empty(&h8_actq)) h8_send_next_cmd_byte(); } else { Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg); @@ -276,10 +275,10 @@ /* If command reception finished. */ if (qp->cnt == qp->nrsp) { h8_state = H8_IDLE; - QUEUE_REMOVE(&h8_actq, qp, link); + list_del(&qp->link); h8_cmd_done (qp); /* More commands to send over? */ - if (!QUEUE_IS_EMPTY(&h8_cmdq, link)) + if (!list_empty(&h8_cmdq)) h8_start_new_cmd(); } return; @@ -317,9 +316,6 @@ misc_register(&h8_device); request_region(h8_base, 8, "h8"); - QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *); - QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *); - QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *); h8_alloc_queues(); h8_hw_init(); @@ -364,9 +360,9 @@ return; } -#ifdef CONFIG_PROC_FS static int h8_get_info(char *buf, char **start, off_t fpos, int length) { +#ifdef CONFIG_PROC_FS char *p; if (!h8_enabled) @@ -387,8 +383,10 @@ ); return p - buf; -} +#else + return 0; #endif +} /* Called from console driver -- must make sure h8_enabled. */ int h8_display_blank(void) @@ -440,7 +438,7 @@ save_flags(flags); cli(); for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) { /* place each at front of freeq */ - QUEUE_ENTER(&h8_freeq, &qp[i], link, h8_cmd_q_t *); + list_add(&qp[i].link, &h8_freeq); } restore_flags(flags); return (1); @@ -458,15 +456,15 @@ /* get cmd buf */ save_flags(flags); cli(); - while (QUEUE_IS_EMPTY(&h8_freeq, link)) { + while (list_empty(&h8_freeq)) { Dprintk("H8: need to allocate more cmd buffers\n"); restore_flags(flags); h8_alloc_queues(); save_flags(flags); cli(); } /* get first element from queue */ - qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_freeq, link); - QUEUE_REMOVE(&h8_freeq, qp, link); + qp = list_entry(h8_freeq.next, h8_cmd_q_t, link); + list_del(&qp->link); restore_flags(flags); @@ -479,7 +477,8 @@ /* queue it at the end of the cmd queue */ save_flags(flags); cli(); - QUEUE_ENTER(&h8_cmdq, qp, link, h8_cmd_q_t *); + /* XXX this actually puts it at the start of cmd queue, bug? */ + list_add(&qp->link, &h8_cmdq); restore_flags(flags); @@ -500,13 +499,13 @@ return; } - if (!QUEUE_IS_EMPTY(&h8_actq, link)) { + if (!list_empty(&h8_actq)) { Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n"); restore_flags(flags); return; } - if (QUEUE_IS_EMPTY(&h8_cmdq, link)) { + if (list_empty(&h8_cmdq)) { Dprintk("h8_start_new_cmd: no command to dequeue\n"); restore_flags(flags); return; @@ -515,9 +514,10 @@ * Take first command off of the command queue and put * it on the active queue. */ - qp = (h8_cmd_q_t *) QUEUE_FIRST(&h8_cmdq, link); - QUEUE_REMOVE(&h8_cmdq, qp, link); - QUEUE_ENTER(&h8_actq, qp, link, h8_cmd_q_t *); + qp = list_entry(h8_cmdq.next, h8_cmd_q_t, link); + list_del(&qp->link); + /* XXX should this go to the end of the active queue? */ + list_add(&qp->link, &h8_actq); h8_state = H8_XMIT; if (h8_debug & 0x1) Dprintk("h8_start_new_cmd: Starting a command\n"); @@ -532,7 +532,7 @@ void h8_send_next_cmd_byte(void) { - h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link); + h8_cmd_q_t *qp = list_entry(h8_actq.next, h8_cmd_q_t, link); int cnt; cnt = qp->cnt; @@ -689,7 +689,7 @@ if (h8_debug & 0x40000) printk("H8: Sync command done - byte returned was 0x%x\n", qp->rcvbuf[0]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_SN: @@ -697,7 +697,7 @@ printk("H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n", qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2], qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_HW_VER: @@ -705,13 +705,13 @@ case H8_RD_MAX_TEMP: printk("H8: Max recorded CPU temp %d, Sys temp %d\n", qp->rcvbuf[0], qp->rcvbuf[1]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_MIN_TEMP: printk("H8: Min recorded CPU temp %d, Sys temp %d\n", qp->rcvbuf[0], qp->rcvbuf[1]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_CURR_TEMP: @@ -719,7 +719,7 @@ xx.byte[0] = qp->rcvbuf[0]; xx.byte[1] = qp->rcvbuf[1]; wake_up(&h8_sync_wait); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_SYS_VARIENT: @@ -740,7 +740,7 @@ xx.byte[0] = qp->rcvbuf[1]; h8_sync_channel |= H8_GET_EXT_STATUS; wake_up(&h8_sync_wait); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_USER_CFG: @@ -755,7 +755,7 @@ case H8_RD_INT_BATT_STATUS: printk("H8: Read int batt status cmd done - returned was %x %x %x\n", qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]); - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_RD_EXT_BATT_STATUS: @@ -767,7 +767,7 @@ printk("H8: Device control cmd done - byte returned was 0x%x\n", qp->rcvbuf[0]); } - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_CTL_TFT_BRT_DC: @@ -788,7 +788,7 @@ XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n", qp->rcvbuf[0]); } - QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *); + list_add(&qp->link, &h8_freeq); break; case H8_CTL_LOWER_TEMP: diff -u --recursive --new-file v2.3.47/linux/drivers/char/h8.h linux/drivers/char/h8.h --- v2.3.47/linux/drivers/char/h8.h Wed Jun 24 14:30:09 1998 +++ linux/drivers/char/h8.h Thu Feb 24 09:13:46 2000 @@ -229,7 +229,7 @@ * H8 command buffers */ typedef struct h8_cmd_q { - DLNODE(struct h8_cmd_q) link; /* double linked list */ + struct list_head link; /* double linked list */ int ncmd; /* number of bytes in command */ int nrsp; /* number of bytes in response */ int cnt; /* number of bytes sent/received */ @@ -237,10 +237,6 @@ u_char cmdbuf[H8_MAX_CMD_SIZE]; /* buffer to store command */ u_char rcvbuf[H8_MAX_CMD_SIZE]; /* buffer to store response */ } h8_cmd_q_t; - -typedef struct __queue_head { - DLNODE(struct h8_cmd_q) link; -} queue_head_t; union intr_buf { u_char byte[2]; diff -u --recursive --new-file v2.3.47/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.3.47/linux/drivers/char/lp.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/char/lp.c Thu Feb 24 10:30:25 2000 @@ -783,12 +783,12 @@ return -EIO; } + devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL); + if (parport_register_driver (&lp_driver)) { printk ("lp: unable to register with parport\n"); return -EIO; } - - devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL); if (!lp_count) { printk (KERN_INFO "lp: driver loaded but no devices found\n"); diff -u --recursive --new-file v2.3.47/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.3.47/linux/drivers/char/mem.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/mem.c Sat Feb 26 20:24:58 2000 @@ -5,6 +5,7 @@ * * Added devfs support. * Jan-11-1998, C. Scott Ananian + * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar */ #include @@ -285,7 +286,7 @@ return do_write_mem(file, (void*)p, p, buf, count, ppos); } -#if !defined(CONFIG_PPC) && !defined(__mc68000__) +#if !defined(__mc68000__) static ssize_t read_port(struct file * file, char * buf, size_t count, loff_t *ppos) { @@ -434,7 +435,7 @@ static int mmap_zero(struct file * file, struct vm_area_struct * vma) { if (vma->vm_flags & VM_SHARED) - return -EINVAL; + return map_zero_setup(vma); if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0; @@ -514,7 +515,7 @@ write: write_null, }; -#if !defined(CONFIG_PPC) && !defined(__mc68000__) +#if !defined(__mc68000__) static struct file_operations port_fops = { llseek: memory_lseek, read: read_port, @@ -548,7 +549,7 @@ case 3: filp->f_op = &null_fops; break; -#if !defined(CONFIG_PPC) && !defined(__mc68000__) +#if !defined(__mc68000__) case 4: filp->f_op = &port_fops; break; diff -u --recursive --new-file v2.3.47/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.3.47/linux/drivers/char/misc.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/misc.c Fri Feb 25 10:26:42 2000 @@ -209,6 +209,9 @@ #if defined(CONFIG_SUN_MOSTEK_RTC) rtc_sun_init(); #endif +#ifdef CONFIG_SGI_DS1286 + ds1286_init(); +#endif #ifdef CONFIG_ATARI_DSP56K dsp56k_init(); #endif @@ -221,7 +224,7 @@ #ifdef CONFIG_SGI_NEWPORT_GFX gfx_register (); #endif -#ifdef CONFIG_SGI +#ifdef CONFIG_SGI_IP22 streamable_init (); #endif #ifdef CONFIG_SGI_NEWPORT_GFX diff -u --recursive --new-file v2.3.47/linux/drivers/char/nwbutton.c linux/drivers/char/nwbutton.c --- v2.3.47/linux/drivers/char/nwbutton.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/nwbutton.c Thu Feb 24 22:56:47 2000 @@ -0,0 +1,276 @@ +/* + * NetWinder Button Driver- + * Copyright (C) Alex Holden 1998, 1999. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#define __NWBUTTON_C /* Tell the header file who we are */ +#include "nwbutton.h" + +static int button_press_count = 0; /* The count of button presses */ +static struct timer_list button_timer; /* Times for the end of a sequence */ +static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */ +static char button_output_buffer[32]; /* Stores data to write out of device */ +static int bcount = 0; /* The number of bytes in the buffer */ +static int bdelay = BUTTON_DELAY; /* The delay, in jiffies */ +static struct button_callback button_callback_list[32]; /* The callback list */ +static int callback_count = 0; /* The number of callbacks registered */ +static int reboot_count = NUM_PRESSES_REBOOT; /* Number of presses to reboot */ + +/* + * This function is called by other drivers to register a callback function + * to be called when a particular number of button presses occurs. + * The callback list is a static array of 32 entries (I somehow doubt many + * people are ever going to want to register more than 32 different actions + * to be performed by the kernel on different numbers of button presses ;). + * However, if an attempt to register a 33rd entry (perhaps a stuck loop + * somewhere registering the same entry over and over?) it will fail to + * do so and return -ENOMEM. If an attempt is made to register a null pointer, + * it will fail to do so and return -EINVAL. + * Because callbacks can be unregistered at random the list can become + * fragmented, so we need to search through the list until we find the first + * free entry. + */ + +int button_add_callback (void (*callback) (void), int count) +{ + int lp = 0; + if (callback_count == 32) { + return -ENOMEM; + } + if (!callback) { + return -EINVAL; + } + callback_count++; + for (; (button_callback_list [lp].callback); lp++); + button_callback_list [lp].callback = callback; + button_callback_list [lp].count = count; + return 0; +} + +/* + * This function is called by other drivers to deregister a callback function. + * If you attempt to unregister a callback which does not exist, it will fail + * with -EINVAL. If there is more than one entry with the same address, + * because it searches the list from end to beginning, it will unregister the + * last one to be registered first (FILO- First In Last Out). + * Note that this is not neccessarily true if the entries are not submitted + * at the same time, because another driver could have unregistered a callback + * between the submissions creating a gap earlier in the list, which would + * be filled first at submission time. + */ + +int button_del_callback (void (*callback) (void)) +{ + int lp = 31; + if (!callback) { + return -EINVAL; + } + while (lp >= 0) { + if ((button_callback_list [lp].callback) == callback) { + button_callback_list [lp].callback = NULL; + button_callback_list [lp].count = 0; + callback_count--; + return 0; + }; + lp--; + }; + return -EINVAL; +} + +/* + * This function is called by button_sequence_finished to search through the + * list of callback functions, and call any of them whose count argument + * matches the current count of button presses. It starts at the beginning + * of the list and works up to the end. It will refuse to follow a null + * pointer (which should never happen anyway). + */ + +static void button_consume_callbacks (int bpcount) +{ + int lp = 0; + for (; lp <= 31; lp++) { + if ((button_callback_list [lp].count) == bpcount) { + if (button_callback_list [lp].callback) { + button_callback_list[lp].callback(); + } + } + } +} + +/* + * This function is called when the button_timer times out. + * ie. When you don't press the button for bdelay jiffies, this is taken to + * mean you have ended the sequence of key presses, and this function is + * called to wind things up (write the press_count out to /dev/button, call + * any matching registered function callbacks, initiate reboot, etc.). + */ + +static void button_sequence_finished (unsigned long parameters) +{ +#ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */ + if (button_press_count == reboot_count) { + kill_proc (1, SIGINT, 1); /* Ask init to reboot us */ + } +#endif /* CONFIG_NWBUTTON_REBOOT */ + button_consume_callbacks (button_press_count); + bcount = sprintf (button_output_buffer, "%d\n", button_press_count); + button_press_count = 0; /* Reset the button press counter */ + wake_up_interruptible (&button_wait_queue); +} + +/* + * This handler is called when the orange button is pressed (GPIO 10 of the + * SuperIO chip, which maps to logical IRQ 26). If the press_count is 0, + * this is the first press, so it starts a timer and increments the counter. + * If it is higher than 0, it deletes the old timer, starts a new one, and + * increments the counter. + */ + +static void button_handler (int irq, void *dev_id, struct pt_regs *regs) +{ + if (button_press_count) { + del_timer (&button_timer); + } + button_press_count++; + init_timer (&button_timer); + button_timer.function = button_sequence_finished; + button_timer.expires = (jiffies + bdelay); + add_timer (&button_timer); +} + +/* + * This function is called when a user space program attempts to read + * /dev/nwbutton. It puts the device to sleep on the wait queue until + * button_sequence_finished writes some data to the buffer and flushes + * the queue, at which point it writes the data out to the device and + * returns the number of characters it has written. This function is + * reentrant, so that many processes can be attempting to read from the + * device at any one time. + */ + +static int button_read (struct file *filp, char *buffer, + size_t count, loff_t *ppos) +{ + interruptible_sleep_on (&button_wait_queue); + return (copy_to_user (buffer, &button_output_buffer, bcount)) + ? -EFAULT : bcount; +} + +/* + * This function is called when a user space process attempts to open the + * device. If the driver is compiled into the kernel it does nothing but + * succeed, but if it is compiled in as a module it also increments the + * module usage count to prevent the module from being removed whilst a + * process has the device open. + */ + +static int button_open (struct inode *inode, struct file *filp) +{ + MOD_INC_USE_COUNT; + return 0; +} + +/* + * This function is called when a user space process attempts to close the + * device. If the driver is compiled into the kernel it does nothing at all, + * but if it is compiled in as a module it also decrements the module usage + * count so that it will be possible to unload the module again once all the + * user processes have closed the device. + */ + +static int button_release (struct inode *inode, struct file *filp) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * This structure is the file operations structure, which specifies what + * callbacks functions the kernel should call when a user mode process + * attempts to perform these operations on the device. + */ + +static struct file_operations button_fops = { + NULL, /* lseek */ + button_read, + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + button_open, + NULL, /* flush */ + button_release, +}; + +/* + * This structure is the misc device structure, which specifies the minor + * device number (158 in this case), the name of the device (for /proc/misc), + * and the address of the above file operations structure. + */ + +static struct miscdevice button_misc_device = { + BUTTON_MINOR, + "nwbutton", + &button_fops, +}; + +/* + * This function is called to initialise the driver, either from misc.c at + * bootup if the driver is compiled into the kernel, or from init_module + * below at module insert time. It attempts to register the device node + * and the IRQ and fails with a warning message if either fails, though + * neither ever should because the device number and IRQ are unique to + * this driver. + */ + +static int __init nwbutton_init(void) +{ + if (!machine_is_netwinder()) + return -ENODEV; + + printk (KERN_INFO "NetWinder Button Driver Version %s (C) Alex Holden " + " 1998.\n", VERSION); + + if (misc_register (&button_misc_device)) { + printk (KERN_WARNING "nwbutton: Couldn't register device 10, " + "%d.\n", BUTTON_MINOR); + return -EBUSY; + } + + if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, SA_INTERRUPT, + "nwbutton", NULL)) { + printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n", + IRQ_NETWINDER_BUTTON); + misc_deregister (&button_misc_device); + return -EIO; + } + return 0; +} + +static void __exit nwbutton_exit (void) +{ + free_irq (IRQ_NETWINDER_BUTTON, NULL); + misc_deregister (&button_misc_device); +} + +EXPORT_NO_SYMBOLS; + +module_init(nwbutton_init); +module_exit(nwbutton_exit); diff -u --recursive --new-file v2.3.47/linux/drivers/char/nwbutton.h linux/drivers/char/nwbutton.h --- v2.3.47/linux/drivers/char/nwbutton.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/nwbutton.h Thu Feb 24 22:56:47 2000 @@ -0,0 +1,48 @@ +#ifndef __NWBUTTON_H +#define __NWBUTTON_H + +/* + * NetWinder Button Driver- + * Copyright (C) Alex Holden 1998, 1999. + */ + +#ifdef __NWBUTTON_C /* Actually compiling the driver itself */ + +/* Various defines: */ + +#define NUM_PRESSES_REBOOT 2 /* How many presses to activate shutdown */ +#define BUTTON_DELAY 30 /* How many jiffies for sequence to end */ +#define VERSION "0.3" /* Driver version number */ +#define BUTTON_MINOR 158 /* Major 10, Minor 158, /dev/nwbutton */ + +/* Structure definitions: */ + +struct button_callback { + void (*callback) (void); + int count; +}; + +/* Function prototypes: */ + +static void button_sequence_finished (unsigned long parameters); +static void button_handler (int irq, void *dev_id, struct pt_regs *regs); +static int button_read (struct file *filp, char *buffer, + size_t count, loff_t *ppos); +static int button_open (struct inode *inode, struct file *filp); +static int button_release (struct inode *inode, struct file *filp); +int button_init (void); +int button_add_callback (void (*callback) (void), int count); +int button_del_callback (void (*callback) (void)); +static void button_consume_callbacks (int bpcount); +#ifdef MODULE +int init_module (void); +void cleanup_module (void); +#endif /* MODULE */ + +#else /* Not compiling the driver itself */ + +extern int button_add_callback (void (*callback) (void), int count); +extern int button_del_callback (void (*callback) (void)); + +#endif /* __NWBUTTON_C */ +#endif /* __NWBUTTON_H */ diff -u --recursive --new-file v2.3.47/linux/drivers/char/nwflash.c linux/drivers/char/nwflash.c --- v2.3.47/linux/drivers/char/nwflash.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/nwflash.c Thu Feb 24 22:56:47 2000 @@ -0,0 +1,708 @@ +/* + * Flash memory interface rev.5 driver for the Intel + * Flash chips used on the NetWinder. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/*****************************************************************************/ +#include + +//#define MINIKERNEL 1 //export flash write, erase routines for MiniKernel + +#ifndef MINIKERNEL +#define MSTATIC static +#else +#define MSTATIC +#endif + +#define NWFLASH_VERSION "6.2" + +MSTATIC void kick_open(void); +MSTATIC int get_flash_id(void); +MSTATIC int erase_block(int nBlock); +MSTATIC int write_block(unsigned long p, const char *buf, int count); +static int open_flash(struct inode *inodep, struct file *filep); +static int release_flash(struct inode *inodep, struct file *filep); +static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg); +static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos); +static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos); +static long long flash_llseek(struct file *file, long long offset, int orig); + +#define KFLASH_SIZE 1024*1024 //1 Meg +#define KFLASH_SIZE4 4*1024*1024 //4 Meg +#define KFLASH_ID 0x89A6 //Intel flash +#define KFLASH_ID4 0xB0D4 //Intel flash 4Meg + +static int flashdebug = 0; //if set - we will display progress msgs + +static int gbWriteEnable = 0; +static int gbWriteBase64Enable = 0; +MSTATIC int gbFlashSize = KFLASH_SIZE; + +extern spinlock_t gpio_lock; + +static struct file_operations flash_fops = +{ + flash_llseek, /* llseek */ + flash_read, /* read */ + flash_write, /* write */ + NULL, /* no special readdir */ + NULL, /* no special select */ + flash_ioctl, + NULL, /* no special mmap */ + open_flash, + NULL, /* no special flush */ + release_flash, + NULL, /* no special fsync */ + NULL, /* no special fasync */ + NULL, /* no special check_media_change */ + NULL /* no special revaldate */ +}; + +static struct miscdevice flash_miscdev = +{ + FLASH_MINOR, + "nwflash", + &flash_fops +}; + +/* + * the delay routine - it is often required to let the flash "breeze"... + */ +void flash_wait(int timeout) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(timeout); +} + +MSTATIC int get_flash_id(void) +{ + volatile unsigned int c1, c2; + + /* + * try to get flash chip ID + */ + kick_open(); + c2 = inb(0x80); + *(unsigned char *) (FLASH_BASE + 0x8000) = 0x90; + udelay(15); + c1 = *(unsigned char *) FLASH_BASE; + c2 = inb(0x80); + + /* + * on 4 Meg flash the second byte is actually at offset 2... + */ + if (c1 == 0xB0) + c2 = *(unsigned char *) (FLASH_BASE + 2); + else + c2 = *(unsigned char *) (FLASH_BASE + 1); + + c2 += (c1 << 8); + + /* + * set it back to read mode + */ + *(unsigned char *) (FLASH_BASE + 0x8000) = 0xFF; + + if (c2 == KFLASH_ID4) + gbFlashSize = KFLASH_SIZE4; + + return c2; +} + +static int open_flash(struct inode *inodep, struct file *filep) +{ + int id; + + id = get_flash_id(); + if ((id != KFLASH_ID) && (id != KFLASH_ID4)) { + printk("Flash: incorrect ID 0x%04X.\n", id); + return -ENXIO; + } + MOD_INC_USE_COUNT; + + return 0; +} + + +static int release_flash(struct inode *inodep, struct file *filep) +{ + MOD_DEC_USE_COUNT; + return 0; +} + + +static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg) +{ +// printk("Flash_ioctl: cmd = 0x%X.\n",cmd); + + switch (cmd) { + case CMD_WRITE_DISABLE: + gbWriteBase64Enable = 0; + gbWriteEnable = 0; + break; + + case CMD_WRITE_ENABLE: + gbWriteEnable = 1; + break; + + case CMD_WRITE_BASE64K_ENABLE: + gbWriteBase64Enable = 1; + break; + + default: + gbWriteBase64Enable = 0; + gbWriteEnable = 0; + return -EINVAL; + } + + return 0; +} + + + +static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos) +{ + unsigned long p = file->f_pos; + int read; + + if (flashdebug) + printk("Flash_dev: flash_read: offset=0x%X, buffer=0x%X, count=0x%X.\n", + (unsigned int) p, (unsigned int) buf, count); + + + if (count < 0) + return -EINVAL; + + if (count > gbFlashSize - p) + count = gbFlashSize - p; + + /* + * flash virtual address + */ + p += FLASH_BASE; + + read = 0; + + if (copy_to_user(buf, (void *) p, count)) + return -EFAULT; + read += count; + file->f_pos += read; + return read; +} + +static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos) +{ + unsigned long p = file->f_pos; + int written; + int nBlock, temp, rc; + int i, j; + + + if (flashdebug) + printk("Flash_dev: flash_write: offset=0x%X, buffer=0x%X, count=0x%X.\n", + (unsigned int) p, (unsigned int) buf, count); + + if (!gbWriteEnable) + return -EINVAL; + + if (p < 64 * 1024 && (!gbWriteBase64Enable)) + return -EINVAL; + + if (count < 0) + return -EINVAL; + + /* + * if write size to big - error! + */ + if (count > gbFlashSize - p) + return -EINVAL; + + + if (verify_area(VERIFY_READ, buf, count)) + return -EFAULT; + + + written = 0; + + leds_event(led_claim); + leds_event(led_green_on); + + nBlock = (int) p >> 16; //block # of 64K bytes + + /* + * # of 64K blocks to erase and write + */ + temp = ((int) (p + count) >> 16) - nBlock + 1; + + /* + * write ends at exactly 64k boundry? + */ + if (((int) (p + count) & 0xFFFF) == 0) + temp -= 1; + + if (flashdebug) + printk("FlashWrite: writing %d block(s) starting at %d.\n", temp, nBlock); + + for (; temp; temp--, nBlock++) { + if (flashdebug) + printk("FlashWrite: erasing block %d.\n", nBlock); + + /* + * first we have to erase the block(s), where we will write... + */ + i = 0; + j = 0; + RetryBlock: + do { + rc = erase_block(nBlock); + i++; + } while (rc && i < 10); + + if (rc) { + if (flashdebug) + printk("FlashWrite: erase error %X. Aborting...\n", rc); + + break; + } + if (flashdebug) + printk("FlashWrite: writing offset %X, from buf %X, bytes left %X.\n", + (unsigned int) p, (unsigned int) buf, count - written); + + /* + * write_block will limit write to space left in this block + */ + rc = write_block(p, buf, count - written); + j++; + + /* + * if somehow write verify failed? Can't happen?? + */ + if (!rc) { + /* + * retry up to 10 times + */ + if (j < 10) + goto RetryBlock; + else + /* + * else quit with error... + */ + rc = -1; + + } + if (rc < 0) { + if (flashdebug) + printk("FlashWrite: write error %X. Aborting...\n", rc); + break; + } + p += rc; + buf += rc; + written += rc; + file->f_pos += rc; + + if (flashdebug) + printk("FlashWrite: written 0x%X bytes OK.\n", written); + } + + /* + * restore reg on exit + */ + leds_event(led_release); + + return written; +} + + +/* + * The memory devices use the full 32/64 bits of the offset, and so we cannot + * check against negative addresses: they are ok. The return value is weird, + * though, in that case (0). + * + * also note that seeking relative to the "end of file" isn't supported: + * it has no meaning, so it returns -EINVAL. + */ +static long long flash_llseek(struct file *file, long long offset, int orig) +{ + if (flashdebug) + printk("Flash_dev: flash_lseek, offset=0x%X, orig=0x%X.\n", + (unsigned int) offset, (unsigned int) orig); + + switch (orig) { + case 0: + if (offset < 0) + return -EINVAL; + + if ((unsigned int) offset > gbFlashSize) + return -EINVAL; + + file->f_pos = (unsigned int) offset; + return file->f_pos; + case 1: + if ((file->f_pos + offset) > gbFlashSize) + return -EINVAL; + if ((file->f_pos + offset) < 0) + return -EINVAL; + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; + } +} + + +/* + * assume that main Write routine did the parameter checking... + * so just go ahead and erase, what requested! + */ + +MSTATIC int erase_block(int nBlock) +{ + volatile unsigned int c1; + volatile unsigned char *pWritePtr; + int temp, temp1; + + /* + * orange LED == erase + */ + leds_event(led_amber_on); + + /* + * reset footbridge to the correct offset 0 (...0..3) + */ + *CSR_ROMWRITEREG = 0; + + /* + * dummy ROM read + */ + c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000); + + kick_open(); + /* + * reset status if old errors + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + /* + * erase a block... + * aim at the middle of a current block... + */ + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + 0x8000 + (nBlock << 16))); + /* + * dummy read + */ + c1 = *pWritePtr; + + kick_open(); + /* + * erase + */ + *(volatile unsigned char *) pWritePtr = 0x20; + + /* + * confirm + */ + *(volatile unsigned char *) pWritePtr = 0xD0; + + /* + * wait 10 ms + */ + flash_wait(HZ / 100); + + /* + * wait while erasing in process (up to 10 sec) + */ + temp = jiffies + 10 * HZ; + c1 = 0; + while (!(c1 & 0x80) && time_before(jiffies, temp)) { + flash_wait(HZ / 100); + /* + * read any address + */ + c1 = *(volatile unsigned char *) (pWritePtr); + // printk("Flash_erase: status=%X.\n",c1); + } + + /* + * set flash for normal read access + */ + kick_open(); +// *(volatile unsigned char*)(FLASH_BASE+0x8000) = 0xFF; + *(volatile unsigned char *) pWritePtr = 0xFF; //back to normal operation + + /* + * check if erase errors were reported + */ + if (c1 & 0x20) { + if (flashdebug) + printk("Flash_erase: err at %X.\n", (unsigned int) pWritePtr); + /* + * reset error + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + return -2; + } + + /* + * just to make sure - verify if erased OK... + */ + flash_wait(HZ / 100); + + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + (nBlock << 16))); + + for (temp = 0; temp < 16 * 1024; temp++, pWritePtr += 4) { + if ((temp1 = *(volatile unsigned int *) pWritePtr) != 0xFFFFFFFF) { + if (flashdebug) + printk("Flash_erase: verify err at %X = %X.\n", + (unsigned int) pWritePtr, temp1); + return -1; + } + } + + return 0; + +} + +/* + * write_block will limit number of bytes written to the space in this block + */ +MSTATIC int write_block(unsigned long p, const char *buf, int count) +{ + volatile unsigned int c1; + volatile unsigned int c2; + unsigned char *pWritePtr; + unsigned int uAddress; + unsigned int offset; + unsigned int timeout; + unsigned int timeout1; + + /* + * red LED == write + */ + leds_event(led_amber_off); + leds_event(led_red_on); + + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); + + /* + * check if write will end in this block.... + */ + offset = p & 0xFFFF; + + if (offset + count > 0x10000) + count = 0x10000 - offset; + + /* + * wait up to 30 sec for this block + */ + timeout = jiffies + 30 * HZ; + + for (offset = 0; offset < count; offset++, pWritePtr++) { + uAddress = (unsigned int) pWritePtr; + uAddress &= 0xFFFFFFFC; + if (__get_user(c2, buf + offset)) + return -EFAULT; + + WriteRetry: + /* + * dummy read + */ + c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000); + + /* + * kick open the write gate + */ + kick_open(); + + /* + * program footbridge to the correct offset...0..3 + */ + *CSR_ROMWRITEREG = (unsigned int) pWritePtr & 3; + + /* + * write cmd + */ + *(volatile unsigned char *) (uAddress) = 0x40; + + /* + * data to write + */ + *(volatile unsigned char *) (uAddress) = c2; + + /* + * get status + */ + *(volatile unsigned char *) (FLASH_BASE + 0x10000) = 0x70; + + c1 = 0; + + /* + * wait up to 1 sec for this byte + */ + timeout1 = jiffies + 1 * HZ; + + /* + * while not ready... + */ + while (!(c1 & 0x80) && time_before(jiffies, timeout1)) + c1 = *(volatile unsigned char *) (FLASH_BASE + 0x8000); + + /* + * if timeout getting status + */ + if (time_after_eq(jiffies, timeout1)) { + kick_open(); + /* + * reset err + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + goto WriteRetry; + } + /* + * switch on read access, as a default flash operation mode + */ + kick_open(); + /* + * read access + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0xFF; + + /* + * if hardware reports an error writing, and not timeout - + * reset the chip and retry + */ + if (c1 & 0x10) { + kick_open(); + /* + * reset err + */ + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50; + + /* + * before timeout? + */ + if (time_before(jiffies, timeout)) { + if (flashdebug) + printk("FlashWrite: Retrying write (addr=0x%X)...\n", + (unsigned int) pWritePtr - FLASH_BASE); + + /* + * no LED == waiting + */ + leds_event(led_amber_off); + /* + * wait couple ms + */ + flash_wait(HZ / 100); + /* + * red LED == write + */ + leds_event(led_red_on); + + goto WriteRetry; + } else { + printk("Timeout in flash write! (addr=0x%X) Aborting...\n", + (unsigned int) pWritePtr - FLASH_BASE); + /* + * return error -2 + */ + return -2; + + } + } + } + + /* + * green LED == read/verify + */ + leds_event(led_amber_off); + leds_event(led_green_on); + + flash_wait(HZ / 100); + + pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p)); + + for (offset = 0; offset < count; offset++) { + char c, c1; + if (__get_user(c, buf)) + return -EFAULT; + buf++; + if ((c1 = *pWritePtr++) != c) { + if (flashdebug) + printk("flash write verify error at 0x%X! (%02X!=%02X) Retrying...\n", + (unsigned int) pWritePtr, c1, c); + return 0; + } + } + + return count; +} + + +MSTATIC void kick_open(void) +{ + unsigned long flags; + + /* + * we want to write a bit pattern XXX1 to Xilinx to enable + * the write gate, which will be open for about the next 2ms. + */ + spin_lock_irqsave(&gpio_lock, flags); + cpld_modify(1, 1); + spin_unlock_irqrestore(&gpio_lock, flags); + + /* + * let the ISA bus to catch on... + */ + udelay(25); +} + +MSTATIC int __init nwflash_init(void) +{ + int ret = -ENODEV; + + if (machine_is_netwinder()) { + int id; + + id = get_flash_id(); + printk("Flash ROM driver v.%s, flash device ID 0x%04X, size %d Mb.\n", + NWFLASH_VERSION, id, gbFlashSize / (1024 * 1024)); + + misc_register(&flash_miscdev); + + ret = 0; + } + + return ret; +} + +MSTATIC void __exit nwflash_exit(void) +{ + misc_deregister(&flash_miscdev); +} + +EXPORT_NO_SYMBOLS; + +MODULE_PARM(flashdebug, "i"); + +module_init(nwflash_init); +module_exit(nwflash_exit); diff -u --recursive --new-file v2.3.47/linux/drivers/char/raw.c linux/drivers/char/raw.c --- v2.3.47/linux/drivers/char/raw.c Thu Feb 10 17:11:08 2000 +++ linux/drivers/char/raw.c Thu Feb 24 10:30:25 2000 @@ -197,7 +197,12 @@ raw_device_bindings[minor] = bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor))); } else { - kdev_t dev=to_kdev_t(raw_device_bindings[minor]->bd_dev); + kdev_t dev; + if (!raw_device_bindings[minor]) { + err = -ENODEV; + break; + } + dev = to_kdev_t(raw_device_bindings[minor]->bd_dev); rq.block_major = MAJOR(dev); rq.block_minor = MINOR(dev); err = copy_to_user((void *) arg, &rq, sizeof(rq)); diff -u --recursive --new-file v2.3.47/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.3.47/linux/drivers/char/rtc.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/char/rtc.c Tue Feb 22 22:39:33 2000 @@ -36,9 +36,11 @@ * 1.09b Jeff Garzik: Modularize, init cleanup * 1.09c Jeff Garzik: SMP cleanup * 1.10 Paul Barton-Davis: add support for async I/O + * 1.10a Andrea Arcangeli: Alpha updates + * 1.10b Andrew Morton: SMP lock fix */ -#define RTC_VERSION "1.10" +#define RTC_VERSION "1.10b" #define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -378,7 +380,7 @@ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { if (yrs > 169) { - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return -EINVAL; } if (yrs >= 100) @@ -704,7 +706,9 @@ free_irq (rtc_irq, &rtc_port); #else release_region (RTC_PORT (0), RTC_IO_EXTENT); +#ifndef __alpha__ free_irq (RTC_IRQ, NULL); +#endif #endif /* __sparc__ */ } diff -u --recursive --new-file v2.3.47/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.3.47/linux/drivers/char/serial.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/serial.c Fri Feb 25 10:26:42 2000 @@ -4183,6 +4183,16 @@ { PCI_VENDOR_ID_ROCKWELL, 0x1004, 0x1048, 0x1500, SPCI_FL_BASE1, 1, 115200 }, +#ifdef CONFIG_DDB5074 + /* + * NEC Vrc-5074 (Nile 4) builtin UART. + * Conditionally compiled in since this is a motherboard device. + */ + { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE0, 1, 520833, + 64, 3, NULL, 0x300 }, +#endif /* Generic serial board */ { 0, 0, 0, 0, diff -u --recursive --new-file v2.3.47/linux/drivers/char/vino.c linux/drivers/char/vino.c --- v2.3.47/linux/drivers/char/vino.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/char/vino.c Fri Feb 25 10:26:42 2000 @@ -1,4 +1,4 @@ -/* $Id: vino.c,v 1.4 1999/02/09 23:59:36 ulfc Exp $ +/* $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. diff -u --recursive --new-file v2.3.47/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.3.47/linux/drivers/char/vt.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/char/vt.c Fri Feb 25 10:26:42 2000 @@ -62,7 +62,7 @@ */ unsigned char keyboard_type = KB_101; -#if !defined(__alpha__) && !defined(__arm__) +#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); #endif @@ -90,7 +90,7 @@ */ #if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \ - || (defined(__mips__) && !defined(CONFIG_SGI)) \ + || (defined(__mips__) && !defined(CONFIG_SGI_IP22)) \ || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) static void @@ -473,7 +473,7 @@ ucval = keyboard_type; goto setchar; -#if !defined(__alpha__) && !defined(__arm__) +#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) /* * These cannot be implemented on any machine that implements * ioperm() in user level (such as Alpha PCs). diff -u --recursive --new-file v2.3.47/linux/drivers/char/wdt285.c linux/drivers/char/wdt285.c --- v2.3.47/linux/drivers/char/wdt285.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/wdt285.c Thu Feb 24 22:56:47 2000 @@ -0,0 +1,204 @@ +/* + * Intel 21285 watchdog driver + * Copyright (c) Phil Blundell , 1998 + * + * based on + * + * SoftDog 0.05: A Software Watchdog Device + * + * (c) Copyright 1996 Alan Cox , All Rights Reserved. + * http://www.cymru.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Define this to stop the watchdog actually rebooting the machine. + */ +#undef ONLY_TESTING + +#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ + +#define FCLK (50*1000*1000) /* 50MHz */ + +static int soft_margin = TIMER_MARGIN; /* in seconds */ +static int timer_alive = 0; + +#ifdef ONLY_TESTING +/* + * If the timer expires.. + */ + +static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_CRIT "Watchdog: Would Reboot.\n"); + *CSR_TIMER4_CNTL = 0; + *CSR_TIMER4_CLR = 0; +} +#endif + +static void watchdog_ping(void) +{ + /* + * Refresh the timer. + */ + *CSR_TIMER4_LOAD = soft_margin * (FCLK / 256); +} + +/* + * Allow only one person to hold it open + */ + +static int watchdog_open(struct inode *inode, struct file *file) +{ + if(timer_alive) + return -EBUSY; + MOD_INC_USE_COUNT; + /* + * Ahead watchdog factor ten, Mr Sulu + */ + *CSR_TIMER4_CLR = 0; + watchdog_ping(); + *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD + | TIMER_CNTL_DIV256; +#ifdef ONLY_TESTING + request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL); +#else + *CSR_SA110_CNTL |= 1 << 13; +#endif + timer_alive = 1; + return 0; +} + +static int watchdog_release(struct inode *inode, struct file *file) +{ +#ifdef ONLY_TESTING + free_irq(IRQ_TIMER4, NULL); + timer_alive = 0; + MOD_DEC_USE_COUNT; +#else + /* + * It's irreversible! + */ +#endif + return 0; +} + +static ssize_t watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* + * Refresh the timer. + */ + if(len) + { + watchdog_ping(); + return 1; + } + return 0; +} + +static int watchdog_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int i; + static struct watchdog_info ident= + { + 0, + 0, + "Footbridge Watchdog" + }; + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct watchdog_info)); + if (i) + return i; + else + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0,(int *)arg); + case WDIOC_KEEPALIVE: + watchdog_ping(); + return 0; + } +} + +static struct file_operations watchdog_fops= +{ + NULL, /* Seek */ + NULL, /* Read */ + watchdog_write, /* Write */ + NULL, /* Readdir */ + NULL, /* Select */ + watchdog_ioctl, /* Ioctl */ + NULL, /* MMap */ + watchdog_open, + NULL, /* flush */ + watchdog_release, + NULL, + NULL /* Fasync */ +}; + +static struct miscdevice watchdog_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &watchdog_fops +}; + +static int __init footbridge_watchdog_init(void) +{ + if (machine_is_netwinder()) + return -ENODEV; + + misc_register(&watchdog_miscdev); + printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n", + soft_margin); + if (machine_is_cats()) + printk("Warning: Watchdog reset may not work on this machine.\n"); + return 0; +} + +static void __exit footbridge_watchdog_exit(void) +{ + misc_deregister(&watchdog_miscdev); +} + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Phil Blundell "); +MODULE_DESCRIPTION("21285 watchdog driver"); + +MODULE_PARM(soft_margin,"i"); +MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds"); + +module_init(footbridge_watchdog_init); +module_exit(footbridge_watchdog_exit); diff -u --recursive --new-file v2.3.47/linux/drivers/char/wdt977.c linux/drivers/char/wdt977.c --- v2.3.47/linux/drivers/char/wdt977.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/wdt977.c Thu Feb 24 22:56:47 2000 @@ -0,0 +1,204 @@ +/* + * Wdt977 0.01: A Watchdog Device for Netwinder W83977AF chip + * + * (c) Copyright 1998 Rebel.com (Woody Suwalski ) + * + * ----------------------- + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * ----------------------- + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define WATCHDOG_MINOR 130 + +static int timeout = 3; +static int timer_alive = 0; +static int testmode = 0; + +/* + * Allow only one person to hold it open + */ + +static int wdt977_open(struct inode *inode, struct file *file) +{ + if(timer_alive) + return -EBUSY; + MOD_INC_USE_COUNT; + timer_alive++; + + //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. + if (timeout>255) + timeout = 255; + + printk(KERN_INFO "Watchdog: active, current timeout %d min.\n",timeout); + + // unlock the SuperIO chip + outb(0x87,0x370); + outb(0x87,0x370); + + //select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 + //F2 has the timeout in minutes + //F3 could be set to the POWER LED blink (with GP17 set to PowerLed) + // at timeout, and to reset timer on kbd/mouse activity (not now) + //F4 is used to just clear the TIMEOUT'ed state (bit 0) + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeout,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); //another setting is 0E for kbd/mouse/LED + outb(0xF4,0x370); + outb(0x00,0x371); + + //at last select device Aux1 (dev=7) and set GP16 as a watchdog output + if (!testmode) + { + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); + } + + // lock the SuperIO chip + outb(0xAA,0x370); + + return 0; +} + +static int wdt977_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we defined ...NOWAYOUT + */ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + + // unlock the SuperIO chip + outb(0x87,0x370); + outb(0x87,0x370); + + //select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 + //F3 is reset to its default state + //F4 can clear the TIMEOUT'ed state (bit 0) - back to default + //We can not use GP17 as a PowerLed, as we use its usage as a RedLed + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(0xFF,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); + outb(0xF4,0x370); + outb(0x00,0x371); + outb(0xF2,0x370); + outb(0x00,0x371); + + //at last select device Aux1 (dev=7) and set GP16 as a watchdog output + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); + + // lock the SuperIO chip + outb(0xAA,0x370); + + MOD_DEC_USE_COUNT; + timer_alive=0; + + printk(KERN_INFO "Watchdog: shutdown.\n"); +#endif + return 0; +} + +static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + + //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. + if (timeout>255) + timeout = 255; + + /* + * Refresh the timer. + */ + + //we have a hw bug somewhere, so each 977 minute is actually only 30sec + //as such limit the max timeout to half of max of 255 minutes... +// if (timeout>126) +// timeout = 126; + + // unlock the SuperIO chip + outb(0x87,0x370); + outb(0x87,0x370); + + //select device Aux2 (device=8) and kicks watchdog reg F2 + //F2 has the timeout in minutes + + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeout,0x371); + + // lock the SuperIO chip + outb(0xAA,0x370); + + return 1; +} + +static struct file_operations wdt977_fops= +{ + NULL, /* Seek */ + NULL, /* Read */ + wdt977_write, /* Write */ + NULL, /* Readdir */ + NULL, /* Select */ + NULL, /* Ioctl */ + NULL, /* MMap */ + wdt977_open, + NULL, /* flush */ + wdt977_release, + NULL, + NULL /* Fasync */ +}; + +static struct miscdevice wdt977_miscdev= +{ + WATCHDOG_MINOR, + "watchdog", + &wdt977_fops +}; + +static int __init nwwatchdog_init(void) +{ + if (!machine_is_netwinder()) + return -ENODEV; + + misc_register(&wdt977_miscdev); + printk(KERN_INFO "NetWinder Watchdog sleeping.\n"); + return 0; +} + +static void __exit nwwatchdog_exit(void) +{ + misc_deregister(&wdt977_miscdev); +} + +EXPORT_NO_SYMBOLS; + +module_init(nwwatchdog_init); +module_exit(nwwatchdog_exit); diff -u --recursive --new-file v2.3.47/linux/drivers/i2c/i2c-core.c linux/drivers/i2c/i2c-core.c --- v2.3.47/linux/drivers/i2c/i2c-core.c Thu Feb 10 17:11:08 2000 +++ linux/drivers/i2c/i2c-core.c Sat Feb 26 20:33:02 2000 @@ -101,10 +101,6 @@ read: i2cproc_bus_read, }; -static struct inode_operations i2cproc_inode_operations = { - &i2cproc_operations -}; - static int i2cproc_initialized = 0; #else /* undef CONFIG_PROC_FS */ @@ -163,7 +159,7 @@ name); return -ENOENT; } - proc_entry->ops = &i2cproc_inode_operations; + proc_entry->proc_fops = &i2cproc_operations; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) proc_entry->owner = THIS_MODULE; #else diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.3.47/linux/drivers/isdn/avmb1/b1dma.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/b1dma.c Sat Feb 26 20:20:12 2000 @@ -1,11 +1,14 @@ /* - * $Id: b1dma.c,v 1.2 2000/01/25 14:44:47 calle Exp $ + * $Id: b1dma.c,v 1.3 2000/02/26 01:00:53 keil Exp $ * * Common module for AVM B1 cards that support dma with AMCC * * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1dma.c,v $ + * Revision 1.3 2000/02/26 01:00:53 keil + * changes from 2.3.47 + * * Revision 1.2 2000/01/25 14:44:47 calle * typo in b1pciv4_detect(). * @@ -31,7 +34,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.2 $"; +static char *revision = "$Revision: 1.3 $"; /* ------------------------------------------------------------- */ diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.3.47/linux/drivers/isdn/avmb1/capi.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/avmb1/capi.c Sat Feb 26 20:20:12 2000 @@ -1,11 +1,14 @@ /* - * $Id: capi.c,v 1.22 1999/11/13 21:27:16 keil Exp $ + * $Id: capi.c,v 1.23 2000/02/26 01:00:53 keil Exp $ * * CAPI 2.0 Interface for Linux * * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: capi.c,v $ + * Revision 1.23 2000/02/26 01:00:53 keil + * changes from 2.3.47 + * * Revision 1.22 1999/11/13 21:27:16 keil * remove KERNELVERSION * diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/divert/divert_procfs.c linux/drivers/isdn/divert/divert_procfs.c --- v2.3.47/linux/drivers/isdn/divert/divert_procfs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/divert/divert_procfs.c Sat Feb 26 20:33:02 2000 @@ -315,8 +315,6 @@ NULL /* fsync */ }; -struct inode_operations divert_file_inode_operations; - /****************************/ /* isdn subdir in /proc/net */ /****************************/ @@ -342,9 +340,7 @@ remove_proc_entry("isdn", proc_net); return (-1); } - memset(&divert_file_inode_operations, 0, sizeof(struct inode_operations)); - divert_file_inode_operations.default_file_ops = &isdn_fops; - isdn_divert_entry->ops = &divert_file_inode_operations; + isdn_divert_entry->proc_fops = &isdn_fops; #endif /* CONFIG_PROC_FS */ return (0); diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/eicon/eicon_idi.c linux/drivers/isdn/eicon/eicon_idi.c --- v2.3.47/linux/drivers/isdn/eicon/eicon_idi.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/eicon/eicon_idi.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.29 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_idi.c,v 1.31 2000/02/22 16:26:40 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * IDI interface @@ -26,6 +26,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.c,v $ + * Revision 1.31 2000/02/22 16:26:40 armin + * Fixed membase error message. + * Fixed missing log buffer struct. + * + * Revision 1.30 2000/02/16 16:08:46 armin + * Fixed virtual channel handling of IDI. + * * Revision 1.29 2000/01/23 21:21:23 armin * Added new trace capability and some updates. * DIVA Server BRI now supports data for ISDNLOG. @@ -149,7 +156,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.29 $"; +char *eicon_idi_revision = "$Revision: 1.31 $"; eicon_manifbuf *manbuf; @@ -255,10 +262,10 @@ } int -idi_put_req(eicon_REQ *reqbuf, int rq, int signet) +idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch) { reqbuf->Req = rq; - reqbuf->ReqCh = 0; + reqbuf->ReqCh = Ch; reqbuf->ReqId = 1; reqbuf->XBuffer.length = 1; reqbuf->XBuffer.P[0] = 0; @@ -368,34 +375,34 @@ break; case REMOVE: case REMOVE|0x700: - idi_put_req(reqbuf, REMOVE, layer); + idi_put_req(reqbuf, REMOVE, layer, 0); break; case INDICATE_REQ: - idi_put_req(reqbuf, INDICATE_REQ, 0); + idi_put_req(reqbuf, INDICATE_REQ, 0, 0); break; case HANGUP: - idi_put_req(reqbuf, HANGUP, 0); + idi_put_req(reqbuf, HANGUP, 0, 0); break; case REJECT: - idi_put_req(reqbuf, REJECT, 0); + idi_put_req(reqbuf, REJECT, 0 ,0); break; case CALL_ALERT: - idi_put_req(reqbuf, CALL_ALERT, 0); + idi_put_req(reqbuf, CALL_ALERT, 0, 0); break; case CALL_RES: idi_call_res_req(reqbuf, chan); break; case IDI_N_CONNECT|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT, 1); + idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0); break; case IDI_N_CONNECT_ACK|0x700: - idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1); + idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0); break; case IDI_N_DISC|0x700: - idi_put_req(reqbuf, IDI_N_DISC, 1); + idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh); break; case IDI_N_DISC_ACK|0x700: - idi_put_req(reqbuf, IDI_N_DISC_ACK, 1); + idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh); break; default: eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No); @@ -813,6 +820,11 @@ message->osa[i] = buffer[pos++]; eicon_log(ccard, 2, "idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa); break; + case CAD: + pos += wlen; + eicon_log(ccard, 2, "idi_inf: Ch%d: Connected Address in ind, len:%x\n", + chan->No, wlen); + break; case BC: if (wlen > sizeof(message->bc)) { pos += wlen; @@ -1206,7 +1218,7 @@ reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ)); reqbuf->Req = IDI_N_EDATA; - reqbuf->ReqCh = 0; + reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; reqbuf->XBuffer.length = idi_fill_in_T30(chan, reqbuf->XBuffer.P); @@ -2205,7 +2217,7 @@ reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ)); reqbuf->Req = IDI_N_UDATA; - reqbuf->ReqCh = 0; + reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; reqbuf->XBuffer.length = len + 1; @@ -2322,7 +2334,7 @@ unsigned char data[1]; } *q; - if (!(p = kmalloc(buflen, GFP_KERNEL))) { + if (!(p = kmalloc(buflen, GFP_ATOMIC))) { eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n"); return; } @@ -2380,7 +2392,7 @@ return; } - if (ind->Ind != 8) + if ((ind->Ind != 8) && (ind->Ind != 0xc)) dlev = 144; else dlev = 128; @@ -2634,6 +2646,7 @@ break; case IDI_N_CONNECT: eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No); + chan->e.IndCh = ind->IndCh; if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1); if (chan->l2prot == ISDN_PROTO_L2_FAX) { break; @@ -2664,6 +2677,7 @@ idi_fax_hangup(ccard, chan); } #endif + chan->e.IndCh = 0; save_flags(flags); cli(); chan->queued = 0; @@ -2693,7 +2707,7 @@ #endif break; case IDI_N_DATA_ACK: - eicon_log(ccard, 16, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); + eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No); break; case IDI_N_DATA: skb_pull(skb, sizeof(eicon_IND) - 1); @@ -2774,6 +2788,11 @@ } else { /* Network layer */ switch(chan->e.Req & 0x0f) { + case IDI_N_CONNECT: + chan->e.IndCh = ack->RcCh; + eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, + ack->RcId, ack->RcCh, ack->Reference); + break; case IDI_N_MDATA: case IDI_N_DATA: if ((chan->e.Req & 0x0f) == IDI_N_DATA) { @@ -2999,7 +3018,7 @@ reqbuf->Req = IDI_N_DATA; if (ack) reqbuf->Req |= N_D_BIT; } - reqbuf->ReqCh = 0; + reqbuf->ReqCh = chan->e.IndCh; reqbuf->ReqId = 1; memcpy(&reqbuf->XBuffer.P, skb->data + offset, plen); reqbuf->XBuffer.length = plen; diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/eicon/eicon_isa.c linux/drivers/isdn/eicon/eicon_isa.c --- v2.3.47/linux/drivers/isdn/eicon/eicon_isa.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/eicon/eicon_isa.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.13 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $ * * ISDN low-level module for Eicon active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -22,6 +22,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_isa.c,v $ + * Revision 1.14 2000/02/22 16:26:40 armin + * Fixed membase error message. + * Fixed missing log buffer struct. + * * Revision 1.13 2000/01/23 21:21:23 armin * Added new trace capability and some updates. * DIVA Server BRI now supports data for ISDNLOG. @@ -83,7 +87,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.13 $"; +char *eicon_isa_revision = "$Revision: 1.14 $"; #undef EICON_MCA_DEBUG @@ -144,6 +148,9 @@ unsigned long amem; if (!strlen(Id)) + return -1; + + if (Mem == -1) return -1; /* Check for valid membase address */ diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c --- v2.3.47/linux/drivers/isdn/eicon/eicon_mod.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/eicon/eicon_mod.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.24 2000/01/23 21:21:23 armin Exp $ +/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -31,6 +31,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_mod.c,v $ + * Revision 1.25 2000/02/22 16:26:40 armin + * Fixed membase error message. + * Fixed missing log buffer struct. + * * Revision 1.24 2000/01/23 21:21:23 armin * Added new trace capability and some updates. * DIVA Server BRI now supports data for ISDNLOG. @@ -140,7 +144,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.24 $"; +static char *eicon_revision = "$Revision: 1.25 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -886,8 +890,10 @@ u_char *p; struct sk_buff *skb; - if (!card) - return; + if (!card) { + if (!(card = cards)) + return; + } save_flags(flags); cli(); diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c --- v2.3.47/linux/drivers/isdn/hisax/avm_pci.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/avm_pci.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: avm_pci.c,v 1.14 1999/12/19 13:09:41 keil Exp $ +/* $Id: avm_pci.c,v 1.15 2000/02/26 00:35:12 keil Exp $ * avm_pci.c low level stuff for AVM Fritz!PCI and ISA PnP isdn cards * Thanks to AVM, Berlin for informations @@ -7,6 +7,9 @@ * * * $Log: avm_pci.c,v $ + * Revision 1.15 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.14 1999/12/19 13:09:41 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays @@ -63,7 +66,7 @@ #include extern const char *CardType[]; -static const char *avm_pci_rev = "$Revision: 1.14 $"; +static const char *avm_pci_rev = "$Revision: 1.15 $"; #define AVM_FRITZ_PCI 1 #define AVM_FRITZ_PNP 2 @@ -499,7 +502,7 @@ if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hdlc.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hdlc.count = 0; bcs->tx_skb = NULL; } @@ -626,7 +629,7 @@ discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c --- v2.3.47/linux/drivers/isdn/hisax/config.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/config.c Sat Feb 26 20:20:12 2000 @@ -1,10 +1,13 @@ -/* $Id: config.c,v 2.43 2000/01/20 19:49:36 keil Exp $ +/* $Id: config.c,v 2.44 2000/02/26 00:35:12 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * * $Log: config.c,v $ + * Revision 2.44 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 2.43 2000/01/20 19:49:36 keil * Support teles 13.3c vendor version 2.1 * @@ -549,9 +552,9 @@ printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); #ifdef MODULE - printk(KERN_INFO "HiSax: Version 3.3d (module)\n"); + printk(KERN_INFO "HiSax: Version 3.3e (module)\n"); #else - printk(KERN_INFO "HiSax: Version 3.3d (kernel)\n"); + printk(KERN_INFO "HiSax: Version 3.3e (kernel)\n"); #endif strcpy(tmp, l1_revision); printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c --- v2.3.47/linux/drivers/isdn/hisax/diva.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/diva.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: diva.c,v 1.18 1999/12/19 13:09:41 keil Exp $ +/* $Id: diva.c,v 1.19 2000/02/26 00:35:12 keil Exp $ * diva.c low level stuff for Eicon.Diehl Diva Family ISDN cards * @@ -12,6 +12,9 @@ * * * $Log: diva.c,v $ + * Revision 1.19 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.18 1999/12/19 13:09:41 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays @@ -84,7 +87,7 @@ extern const char *CardType[]; -const char *Diva_revision = "$Revision: 1.18 $"; +const char *Diva_revision = "$Revision: 1.19 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -585,7 +588,7 @@ if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/elsa_ser.c linux/drivers/isdn/hisax/elsa_ser.c --- v2.3.47/linux/drivers/isdn/hisax/elsa_ser.c Thu Nov 11 20:11:37 1999 +++ linux/drivers/isdn/hisax/elsa_ser.c Sat Feb 26 20:20:12 2000 @@ -298,7 +298,7 @@ (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } } @@ -442,13 +442,13 @@ bcs->hw.hscx.rcvbuf = NULL; } while ((skb = skb_dequeue(&bcs->rqueue))) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } while ((skb = skb_dequeue(&bcs->squeue))) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c --- v2.3.47/linux/drivers/isdn/hisax/hfc_2bds0.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/hfc_2bds0.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: hfc_2bds0.c,v 1.11 1999/12/23 15:09:32 keil Exp $ +/* $Id: hfc_2bds0.c,v 1.12 2000/02/26 00:35:12 keil Exp $ * * specific routines for CCD's HFC 2BDS0 * @@ -6,6 +6,9 @@ * * * $Log: hfc_2bds0.c,v $ + * Revision 1.12 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.11 1999/12/23 15:09:32 keil * change email * @@ -293,7 +296,7 @@ sti(); debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; } else { cli(); @@ -309,7 +312,7 @@ bcs->channel, chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC bcs->err_crc++; @@ -401,7 +404,7 @@ if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } WaitForBusy(cs); @@ -603,7 +606,7 @@ discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } @@ -751,7 +754,7 @@ sti(); debugl1(cs, "RFIFO D BUSY error"); printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n"); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC cs->err_rx++; @@ -770,7 +773,7 @@ chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); skb = NULL; #ifdef ERROR_STATISTIC cs->err_crc++; @@ -870,7 +873,7 @@ cli(); WaitNoBusy(cs); ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND); - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; sti(); WaitForBusy(cs); @@ -1004,7 +1007,7 @@ } goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c --- v2.3.47/linux/drivers/isdn/hisax/hfc_2bs0.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/hfc_2bs0.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: hfc_2bs0.c,v 1.12 1999/12/19 14:17:12 keil Exp $ +/* $Id: hfc_2bs0.c,v 1.13 2000/02/26 00:35:12 keil Exp $ * specific routines for CCD's HFC 2BS0 * @@ -6,6 +6,9 @@ * * * $Log: hfc_2bs0.c,v $ + * Revision 1.13 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.12 1999/12/19 14:17:12 keil * fix compiler warning * @@ -249,7 +252,7 @@ if (idx != count) { debugl1(cs, "RFIFO BUSY error"); printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); if (bcs->mode != L1_MODE_TRANS) { WaitNoBusy(cs); stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | @@ -270,7 +273,7 @@ bcs->channel, chksum, stat); if (stat) { debugl1(cs, "FIFO CRC error"); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); skb = NULL; #ifdef ERROR_STATISTIC bcs->err_crc++; @@ -359,7 +362,7 @@ bcs->tx_cnt -= count; if (PACKET_NOACK == bcs->tx_skb->pkt_type) count = -1; - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; if (bcs->mode != L1_MODE_TRANS) { WaitForBusy(cs); @@ -573,7 +576,7 @@ discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.3.47/linux/drivers/isdn/hisax/hfc_pci.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/hfc_pci.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.26 2000/02/09 20:22:55 werner Exp $ +/* $Id: hfc_pci.c,v 1.27 2000/02/26 00:35:12 keil Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -23,6 +23,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_pci.c,v $ + * Revision 1.27 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.26 2000/02/09 20:22:55 werner * * Updated PCI-ID table @@ -126,7 +129,7 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.26 $"; +static const char *hfcpci_revision = "$Revision: 1.27 $"; /* table entry in the PCI devices list */ typedef struct { @@ -636,7 +639,7 @@ df->f1 = new_f1; /* next frame */ restore_flags(flags); - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; return; } @@ -710,7 +713,7 @@ debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded", bcs->channel, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); cli(); bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */ sti(); @@ -778,7 +781,7 @@ bz->f1 = new_f1; /* next frame */ restore_flags(flags); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); return; @@ -1130,7 +1133,7 @@ } goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -1522,7 +1525,7 @@ discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/hfc_sx.c linux/drivers/isdn/hisax/hfc_sx.c --- v2.3.47/linux/drivers/isdn/hisax/hfc_sx.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/hfc_sx.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: hfc_sx.c,v 1.3 2000/01/20 19:49:36 keil Exp $ +/* $Id: hfc_sx.c,v 1.4 2000/02/26 00:35:12 keil Exp $ * hfc_sx.c low level driver for CCD´s hfc-s+/sp based cards * @@ -22,6 +22,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_sx.c,v $ + * Revision 1.4 2000/02/26 00:35:12 keil + * Fix skb freeing in interrupt context + * * Revision 1.3 2000/01/20 19:49:36 keil * Support teles 13.3c vendor version 2.1 * @@ -38,6 +41,7 @@ * */ +#include #define __NO_VERSION__ #include "hisax.h" #include "hfc_sx.h" @@ -46,7 +50,7 @@ extern const char *CardType[]; -static const char *hfcsx_revision = "$Revision: 1.3 $"; +static const char *hfcsx_revision = "$Revision: 1.4 $"; /***************************************/ /* IRQ-table for CCDs demo board */ @@ -327,7 +331,7 @@ Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */ Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */ if (Read_hfc(cs, HFCSX_FIF_DRD)) { - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); if (cs->debug & L1_DEB_ISAC_FIFO) debugl1(cs, "hfcsx_read_fifo %d crc error", fifo); skb = NULL; @@ -600,7 +604,7 @@ return; if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } return; @@ -633,7 +637,7 @@ if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } @@ -777,7 +781,7 @@ } else HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len); } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } } while (--count && skb); @@ -931,7 +935,7 @@ } goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -1305,7 +1309,7 @@ discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h --- v2.3.47/linux/drivers/isdn/hisax/hisax.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/hisax.h Sat Feb 26 20:20:12 2000 @@ -1,8 +1,11 @@ -/* $Id: hisax.h,v 2.40 2000/01/20 19:51:46 keil Exp $ +/* $Id: hisax.h,v 2.41 2000/02/26 00:35:13 keil Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 2.41 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 2.40 2000/01/20 19:51:46 keil * Fix AddTimer message * Change CONFIG defines @@ -157,8 +160,9 @@ #include #include #include +#include -#undef ERROR_STATISTIC +#define ERROR_STATISTIC #define REQUEST 0 #define CONFIRM 1 diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/hscx.c linux/drivers/isdn/hisax/hscx.c --- v2.3.47/linux/drivers/isdn/hisax/hscx.c Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/hisax/hscx.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: hscx.c,v 1.17 1999/07/01 08:11:41 keil Exp $ +/* $Id: hscx.c,v 1.18 2000/02/26 00:35:13 keil Exp $ * hscx.c HSCX specific routines * @@ -6,6 +6,9 @@ * * * $Log: hscx.c,v $ + * Revision 1.18 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.17 1999/07/01 08:11:41 keil * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel * @@ -219,7 +222,7 @@ discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/hscx_irq.c linux/drivers/isdn/hisax/hscx_irq.c --- v2.3.47/linux/drivers/isdn/hisax/hscx_irq.c Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/hisax/hscx_irq.c Sat Feb 26 20:20:12 2000 @@ -1,4 +1,4 @@ -/* $Id: hscx_irq.c,v 1.13 1999/10/14 20:25:28 keil Exp $ +/* $Id: hscx_irq.c,v 1.14 2000/02/26 00:35:13 keil Exp $ * hscx_irq.c low level b-channel stuff for Siemens HSCX * @@ -7,6 +7,9 @@ * This is an include file for fast inline IRQ stuff * * $Log: hscx_irq.c,v $ + * Revision 1.14 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.13 1999/10/14 20:25:28 keil * add a statistic for error monitoring * @@ -250,7 +253,7 @@ if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/isac.c linux/drivers/isdn/hisax/isac.c --- v2.3.47/linux/drivers/isdn/hisax/isac.c Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/hisax/isac.c Sat Feb 26 20:20:13 2000 @@ -1,4 +1,4 @@ -/* $Id: isac.c,v 1.24 1999/10/14 20:25:28 keil Exp $ +/* $Id: isac.c,v 1.25 2000/02/26 00:35:13 keil Exp $ * isac.c ISAC specific routines * @@ -9,6 +9,9 @@ * ../../../Documentation/isdn/HiSax.cert * * $Log: isac.c,v $ + * Revision 1.25 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.24 1999/10/14 20:25:28 keil * add a statistic for error monitoring * @@ -338,7 +341,7 @@ isac_fill_fifo(cs); goto afterXPR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -627,7 +630,7 @@ discard_queue(&cs->rq); discard_queue(&cs->sq); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) @@ -683,7 +686,7 @@ /* discard frame; reset transceiver */ test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } else { diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c --- v2.3.47/linux/drivers/isdn/hisax/isar.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/isar.c Sat Feb 26 20:20:13 2000 @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $ +/* $Id: isar.c,v 1.10 2000/02/26 00:35:13 keil Exp $ * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -6,6 +6,9 @@ * * * $Log: isar.c,v $ + * Revision 1.10 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.9 2000/01/20 19:47:45 keil * Add Fax Class 1 support * @@ -774,7 +777,7 @@ } } } - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->hw.isar.txcnt = 0; bcs->tx_skb = NULL; } @@ -1631,7 +1634,7 @@ discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); if (bcs->cs->debug & L1_DEB_HSCX) diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/jade.c linux/drivers/isdn/hisax/jade.c --- v2.3.47/linux/drivers/isdn/hisax/jade.c Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/hisax/jade.c Sat Feb 26 20:20:13 2000 @@ -1,10 +1,13 @@ -/* $Id: jade.c,v 1.2 1999/07/01 08:07:57 keil Exp $ +/* $Id: jade.c,v 1.3 2000/02/26 00:35:13 keil Exp $ * * jade.c JADE stuff (derived from original hscx.c) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: jade.c,v $ + * Revision 1.3 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.2 1999/07/01 08:07:57 keil * Initial version * @@ -214,7 +217,7 @@ discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/jade_irq.c linux/drivers/isdn/hisax/jade_irq.c --- v2.3.47/linux/drivers/isdn/hisax/jade_irq.c Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/hisax/jade_irq.c Sat Feb 26 20:20:13 2000 @@ -1,10 +1,13 @@ -/* $Id: jade_irq.c,v 1.2 1999/07/01 08:07:59 keil Exp $ +/* $Id: jade_irq.c,v 1.3 2000/02/26 00:35:13 keil Exp $ * * jade_irq.c Low level JADE IRQ stuff (derived from original hscx_irq.c) * * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: jade_irq.c,v $ + * Revision 1.3 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.2 1999/07/01 08:07:59 keil * Initial version * @@ -192,7 +195,7 @@ if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.hscx.count = 0; bcs->tx_skb = NULL; } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/l3dss1.c linux/drivers/isdn/hisax/l3dss1.c --- v2.3.47/linux/drivers/isdn/hisax/l3dss1.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/l3dss1.c Sat Feb 26 20:20:13 2000 @@ -1,4 +1,4 @@ -/* $Id: l3dss1.c,v 2.22 2000/01/20 19:44:20 keil Exp $ +/* $Id: l3dss1.c,v 2.23 2000/02/26 01:38:14 keil Exp $ * EURO/DSS1 D-channel protocol * @@ -13,6 +13,9 @@ * Fritz Elfert * * $Log: l3dss1.c,v $ + * Revision 2.23 2000/02/26 01:38:14 keil + * Fixes for V.110 encoding LLC from Jens Jakobsen + * * Revision 2.22 2000/01/20 19:44:20 keil * Fixed uninitialiesed location * Fixed redirecting number IE in Setup @@ -104,7 +107,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.22 $"; +const char *dss1_revision = "$Revision: 2.23 $"; #define EXT_BEARER_CAPS 1 @@ -1045,7 +1048,8 @@ EncodeASyncParams(u_char * p, u_char si2) { // 7c 06 88 90 21 42 00 bb - p[0] = p[1] = 0; + p[0] = 0; + p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 p[2] = 0x80; if (si2 & 32) // 7 data bits @@ -1059,7 +1063,7 @@ p[2] += 96; else // 1 stop bit - p[2] = 32; + p[2] += 32; if (si2 & 8) // even parity diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc --- v2.3.47/linux/drivers/isdn/hisax/md5sums.asc Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/hisax/md5sums.asc Sat Feb 26 20:20:13 2000 @@ -6,26 +6,26 @@ # Eicon Technology Diva 2.01 PCI cards in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -3c2b1c96274cba97a8261d1cecc662b8 isac.c -a9a15d069dbacb383cc24c238cb5ebbe isdnl1.c +3fb9c99465857a4c136ae2881f4e30ba isac.c +dd3955847bbf680b41233478fe521d88 isdnl1.c bb51bd223040b511c18f091da5ab6456 isdnl2.c b7aa7f97b2374967a4aca7c52991142c isdnl3.c a23fbf8879c1432b04640b8b04bdf419 tei.c -d7072dbbeeb7c4c45f3810ed13cf5545 callc.c +ce248e56c2e1326012d0b25f92bbf99b callc.c bf9605b36429898f7be6630034e83230 cert.c -0e500813968adacaea2ef22c9cdd89eb l3dss1.c -2d748ced0eea375b21fe7ea91ca7917c l3_1tr6.c -d45fde1c90dda636ab134f2a51db435e elsa.c -0b5fb429f5bfe188fd42a5be01abbb14 diva.c +6ce0a184127be1a44747e2017ed24ad9 l3dss1.c +a3a570781f828b6d59e6b231653133de l3_1tr6.c +4aeba32c4c3480d2a6b9af34600b974f elsa.c +a296edc459b508bf0346c3132815a4db diva.c # end of md5sums -----BEGIN PGP SIGNATURE----- Version: 2.6.3i Charset: noconv -iQCVAwUBOCYF6jpxHvX/mS9tAQFnxQP/dpHyNjbo5BhFEZ8qIgpPJzoCgV+b2pB+ -h9Z/Q1jg8l23L/lP9dW00ogrKnKziVUUJqg+wWVEAA7BnNVr3aeyQKFTVuOnK5MC -Oy0Z98p530vgOBiZ47elNfpefjhfD3duSSYNA4R9fEHVZB/atKFYvB5GDGmrwjIZ -2f3g3kBP5Os= -=zNnO +iQCVAwUBOLcvXDpxHvX/mS9tAQGPWAP9Fg14RXcAwjCy4VeFoDBMOFpxllvG7xZR +HQKENCYIzXKPb6I/IBUv3+BhL8Lnhjw8a2DXz6c6u+0nmUIFnzyt1BfzT70P9rKd +BBN7f1KdIiQEmv0fZwd79Rz5PYvRDbY520bNTJZhorwqGI/qc3gGgHVtSR8OHhuS +ZMQ1pb9W6jE= +=CA5N -----END PGP SIGNATURE----- diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c --- v2.3.47/linux/drivers/isdn/hisax/netjet.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hisax/netjet.c Sat Feb 26 20:20:13 2000 @@ -1,4 +1,4 @@ -/* $Id: netjet.c,v 1.17 1999/12/19 13:09:42 keil Exp $ +/* $Id: netjet.c,v 1.18 2000/02/26 00:35:13 keil Exp $ * netjet.c low level stuff for Traverse Technologie NETJet ISDN cards * @@ -7,6 +7,9 @@ * Thanks to Traverse Technologie Australia for documents and informations * * $Log: netjet.c,v $ + * Revision 1.18 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.17 1999/12/19 13:09:42 keil * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for * signal proof delays @@ -85,7 +88,7 @@ extern const char *CardType[]; -const char *NETjet_revision = "$Revision: 1.17 $"; +const char *NETjet_revision = "$Revision: 1.18 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -730,7 +733,7 @@ if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); @@ -873,7 +876,7 @@ discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hisax/w6692.c linux/drivers/isdn/hisax/w6692.c --- v2.3.47/linux/drivers/isdn/hisax/w6692.c Thu Nov 11 20:11:38 1999 +++ linux/drivers/isdn/hisax/w6692.c Sat Feb 26 20:20:13 2000 @@ -1,4 +1,4 @@ -/* $Id: w6692.c,v 1.1 1999/09/04 06:28:58 keil Exp $ +/* $Id: w6692.c,v 1.2 2000/02/26 00:35:13 keil Exp $ * w6692.c Winbond W6692 specific routines * @@ -8,6 +8,9 @@ * This file is (c) under GNU PUBLIC LICENSE * * $Log: w6692.c,v $ + * Revision 1.2 2000/02/26 00:35:13 keil + * Fix skb freeing in interrupt context + * * Revision 1.1 1999/09/04 06:28:58 keil * first revision * @@ -47,7 +50,7 @@ extern const char *CardType[]; -const char *w6692_revision = "$Revision: 1.1 $"; +const char *w6692_revision = "$Revision: 1.2 $"; #define DBUSY_TIMER_VALUE 80 @@ -378,7 +381,7 @@ if (bcs->st->lli.l1writewakeup && (PACKET_NOACK != bcs->tx_skb->pkt_type)) bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.w6692.count); - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_irq(bcs->tx_skb); bcs->hw.w6692.count = 0; bcs->tx_skb = NULL; } @@ -478,7 +481,7 @@ W6692_fill_fifo(cs); goto afterXFR; } else { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_irq(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } @@ -655,7 +658,7 @@ discard_queue(&cs->rq); discard_queue(&cs->sq); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_skb = NULL; } if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) @@ -704,7 +707,7 @@ /* discard frame; reset transceiver */ test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); + dev_kfree_skb_any(cs->tx_skb); cs->tx_cnt = 0; cs->tx_skb = NULL; } else { @@ -819,7 +822,7 @@ discard_queue(&bcs->rqueue); discard_queue(&bcs->squeue); if (bcs->tx_skb) { - dev_kfree_skb(bcs->tx_skb); + dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hysdn/hysdn_procconf.c linux/drivers/isdn/hysdn/hysdn_procconf.c --- v2.3.47/linux/drivers/isdn/hysdn/hysdn_procconf.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hysdn/hysdn_procconf.c Sat Feb 26 20:33:02 2000 @@ -416,8 +416,6 @@ NULL /* fsync */ }; -static struct inode_operations conf_inode_operations; - /*****************************/ /* hysdn subdir in /proc/net */ /*****************************/ @@ -446,10 +444,8 @@ if ((card->procconf = (void *) create_proc_entry(conf_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { - memset(&conf_inode_operations, 0, sizeof(struct inode_operations)); - conf_inode_operations.default_file_ops = &conf_fops; - ((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations; + ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops; hysdn_proclog_init(card); /* init the log file entry */ } card = card->next; /* next entry */ diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hysdn/hysdn_procfs.c linux/drivers/isdn/hysdn/hysdn_procfs.c --- v2.3.47/linux/drivers/isdn/hysdn/hysdn_procfs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hysdn/hysdn_procfs.c Sat Feb 26 20:33:02 2000 @@ -351,27 +351,6 @@ NULL /* fsync */ }; -struct inode_operations log_inode_operations = -{ - &log_fops, /* log proc file-ops */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* bmap */ - NULL, /* truncate */ - NULL /* permission */ -}; - /*****************************************/ /* Output info data to the cardinfo file */ /*****************************************/ @@ -464,7 +443,7 @@ sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) - pd->log->ops = &log_inode_operations; /* set new operations table */ + pd->log->proc_fops = &log_fops; /* set new operations table */ init_waitqueue_head(&(pd->rd_queue)); diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/hysdn/hysdn_proclog.c linux/drivers/isdn/hysdn/hysdn_proclog.c --- v2.3.47/linux/drivers/isdn/hysdn/hysdn_proclog.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/hysdn/hysdn_proclog.c Sat Feb 26 20:33:02 2000 @@ -433,8 +433,6 @@ NULL /* fsync */ }; -struct inode_operations log_inode_operations; - /***********************************************************************************/ /* hysdn_proclog_init is called when the module is loaded after creating the cards */ /* conf files. */ @@ -448,12 +446,10 @@ if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { memset(pd, 0, sizeof(struct procdata)); - memset(&log_inode_operations, 0, sizeof(struct inode_operations)); - log_inode_operations.default_file_ops = &log_fops; sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) - pd->log->ops = &log_inode_operations; /* set new operations table */ + pd->log->proc_fops = &log_fops; /* set new operations table */ init_waitqueue_head(&(pd->rd_queue)); diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v2.3.47/linux/drivers/isdn/isdn_common.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/isdn_common.c Sat Feb 26 20:20:13 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.97 2000/01/23 18:45:37 keil Exp $ +/* $Id: isdn_common.c,v 1.99 2000/02/26 01:00:52 keil Exp $ * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.99 2000/02/26 01:00:52 keil + * changes from 2.3.47 + * + * Revision 1.98 2000/02/16 14:56:27 paul + * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers + * * Revision 1.97 2000/01/23 18:45:37 keil * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) * @@ -443,7 +449,7 @@ isdn_dev *dev = (isdn_dev *) 0; -static char *isdn_revision = "$Revision: 1.97 $"; +static char *isdn_revision = "$Revision: 1.99 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -1795,15 +1801,15 @@ int i; if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) + (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS))) return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (copy_to_user(p, dev->mdm.info[i].emu.profile, - ISDN_MODEM_ANZREG)) + ISDN_MODEM_NUMREG)) return -EFAULT; - p += ISDN_MODEM_ANZREG; + p += ISDN_MODEM_NUMREG; if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; @@ -1811,7 +1817,7 @@ return -EFAULT; p += ISDN_LMSNLEN; } - return (ISDN_MODEM_ANZREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; + return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; } else return -EINVAL; break; @@ -1822,15 +1828,15 @@ int i; if ((ret = verify_area(VERIFY_READ, (void *) arg, - (ISDN_MODEM_ANZREG + ISDN_MSNLEN) + (ISDN_MODEM_NUMREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS))) return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (copy_from_user(dev->mdm.info[i].emu.profile, p, - ISDN_MODEM_ANZREG)) + ISDN_MODEM_NUMREG)) return -EFAULT; - p += ISDN_MODEM_ANZREG; + p += ISDN_MODEM_NUMREG; if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; @@ -2632,7 +2638,7 @@ devfs_unregister (devfs_handle); } -#else /* CONFIG_DEVFS_FS */ +#else /* CONFIG_DEVFS_FS */ static void isdn_register_devfs(int dummy) { return; @@ -2653,7 +2659,7 @@ return; } -#endif /* CONFIG_DEVFS_FS */ +#endif /* CONFIG_DEVFS_FS */ /* * Allocate and initialize all data, register modem-devices diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.3.47/linux/drivers/isdn/isdn_net.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/isdn/isdn_net.c Sat Feb 26 20:20:13 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.107 2000/02/13 09:52:05 kai Exp $ +/* $Id: isdn_net.c,v 1.110 2000/02/26 01:00:53 keil Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.110 2000/02/26 01:00:53 keil + * changes from 2.3.47 + * + * Revision 1.109 2000/02/25 11:29:17 paul + * changed chargetime to ulong from int (after about 20 days the "chargetime of + * ipppX is now 1234" message displays a negative number on alpha). + * + * Revision 1.108 2000/02/15 12:54:01 kai + * set TX timeout back to 2 secs for 2.2.x, just to be safe + * * Revision 1.107 2000/02/13 09:52:05 kai * increased TX_TIMEOUT to 20sec * @@ -521,6 +531,14 @@ netif_wake_queue(&lp->netdev->dev); } +/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just + * to be safe. + * For 2.3.x we push it up to 20 secs, because call establishment + * (in particular callback) may take such a long time, and we + * don't want confusing messages in the log. However, there is a slight + * possibility that this large timeout will break other things like MPPP, + * which might rely on the tx timeout. If so, we'll find out this way... + */ #define ISDN_NET_TX_TIMEOUT (20*HZ) @@ -530,7 +548,7 @@ static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.107 $"; +char *isdn_net_revision = "$Revision: 1.110 $"; /* * Code for raw-networking over ISDN @@ -727,7 +745,7 @@ isdn_net_hangup(&p->dev); } else if (jiffies - l->chargetime > l->chargeint) { printk(KERN_DEBUG - "isdn_net: %s: chtime = %d, chint = %d\n", + "isdn_net: %s: chtime = %lu, chint = %d\n", l->name, l->chargetime, l->chargeint); isdn_net_hangup(&p->dev); } @@ -868,7 +886,7 @@ * we correct the timestamp here. */ lp->chargetime = jiffies; - printk(KERN_DEBUG "isdn_net: chargetime of %s now %d\n", + printk(KERN_DEBUG "isdn_net: chargetime of %s now %lu\n", lp->name, lp->chargetime); /* reset dial-timeout */ @@ -915,7 +933,7 @@ if (lp->hupflags & ISDN_WAITCHARGE) lp->hupflags |= ISDN_HAVECHARGE; lp->chargetime = jiffies; - printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %d\n", + printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n", lp->name, lp->chargetime); return 1; } diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.3.47/linux/drivers/isdn/isdn_tty.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/isdn_tty.c Sat Feb 26 20:20:13 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.82 2000/01/23 18:45:37 keil Exp $ +/* $Id: isdn_tty.c,v 1.84 2000/02/16 15:10:14 paul Exp $ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -20,6 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.84 2000/02/16 15:10:14 paul + * If a ttyI has no open FDs, don't connect incoming calls to it. + * (Hangup on close of last FD is still to be done.) + * + * Revision 1.83 2000/02/16 14:59:33 paul + * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers; + * used defines for result codes; + * fixed RING ... RUNG problem (no empty lines in between). + * * Revision 1.82 2000/01/23 18:45:37 keil * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN) * @@ -379,7 +388,7 @@ static int si2bit[8] = {4, 1, 4, 4, 4, 4, 4, 4}; -char *isdn_tty_revision = "$Revision: 1.82 $"; +char *isdn_tty_revision = "$Revision: 1.84 $"; /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() @@ -901,7 +910,7 @@ isdn_tty_modem_do_ncarrier(unsigned long data) { modem_info *info = (modem_info *) data; - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); } /* Next routine is called, whenever the DTR-signal is raised. @@ -986,7 +995,7 @@ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { info->isdn_driver = dev->drvmap[i]; info->isdn_channel = dev->chanmap[i]; @@ -1056,8 +1065,7 @@ if (info->online) { info->last_lhup = local; info->online = 0; - /* NO CARRIER message */ - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); } #ifdef CONFIG_ISDN_AUDIO info->vonline = 0; @@ -1086,7 +1094,7 @@ #endif if ((info->msr & UART_MSR_RI) && (info->emu.mdmreg[REG_RUNG] & BIT_RUNG)) - isdn_tty_modem_result(12, info); + isdn_tty_modem_result(RESULT_RUNG, info); info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); info->lsr |= UART_LSR_TEMT; if (info->isdn_driver >= 0) { @@ -1197,7 +1205,7 @@ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { info->isdn_driver = dev->drvmap[i]; info->isdn_channel = dev->chanmap[i]; @@ -1265,7 +1273,7 @@ l = strlen(msg); if (!l) { - isdn_tty_modem_result(4, info); + isdn_tty_modem_result(RESULT_ERROR, info); return; } for (j = 7; j >= 0; j--) @@ -1291,7 +1299,7 @@ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } else { info->isdn_driver = dev->drvmap[i]; info->isdn_channel = dev->chanmap[i]; @@ -1589,7 +1597,7 @@ #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in isdn_tty_write\n"); #endif - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); isdn_tty_modem_hup(info, 1); } else c = isdn_tty_edit_at(buf, c, info, from_user); @@ -2321,7 +2329,7 @@ { atemu *m = &info->emu; if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) { - memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG); + memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG); memcpy(m->msn, m->pmsn, ISDN_MSNLEN); memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN); info->xmit_size = m->mdmreg[REG_PSIZE] * 16; @@ -2338,7 +2346,7 @@ static void modem_write_profile(atemu * m) { - memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG); + memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG); memcpy(m->pmsn, m->msn, ISDN_MSNLEN); memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); if (dev->profd) @@ -2447,6 +2455,13 @@ return 0; } + +/* + * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx) + * match the MSN against the MSNs (glob patterns) defined for tty_emulator, + * and return 0 for match, 1 for no match, 2 if MSN could match if longer. + */ + static int isdn_tty_match_icall(char *cid, atemu *emu, int di) { @@ -2512,15 +2527,14 @@ int idx; int si1; int si2; - char nr[32]; + char *nr; ulong flags; if (!setup.phone[0]) { - nr[0] = '0'; - nr[1] = '\0'; + nr = "0"; printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n"); } else - strcpy(nr, setup.phone); + nr = setup.phone; si1 = (int) setup.si1; si2 = (int) setup.si2; if (!setup.eazmsn[0]) { @@ -2537,6 +2551,8 @@ for (i = 0; i < ISDN_MAX_CHANNELS; i++) { modem_info *info = &dev->mdm.info[i]; + if (info->count == 0) + continue; if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ idx = isdn_dc2minor(di, ch); @@ -2574,7 +2590,7 @@ printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, info->line); info->msr |= UART_MSR_RI; - isdn_tty_modem_result(2, info); + isdn_tty_modem_result(RESULT_RING, info); isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); return 1; } @@ -2660,9 +2676,9 @@ #endif if (TTY_IS_ACTIVE(info)) { if (info->dialing == 1) - isdn_tty_modem_result(7, info); + isdn_tty_modem_result(RESULT_BUSY, info); if (info->dialing > 1) - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); info->dialing = 0; #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); @@ -2691,12 +2707,12 @@ if (USG_MODEM(dev->usage[i])) { if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) { strcpy(info->emu.connmsg, c->parm.num); - isdn_tty_modem_result(1, info); + isdn_tty_modem_result(RESULT_CONNECT, info); } else - isdn_tty_modem_result(5, info); + isdn_tty_modem_result(RESULT_CONNECT64000, info); } if (USG_VOICE(dev->usage[i])) - isdn_tty_modem_result(11, info); + isdn_tty_modem_result(RESULT_VCON, info); return 1; } break; @@ -2722,7 +2738,7 @@ info->last_l2 = -1; info->last_si = 0; sprintf(info->last_cause, "0000"); - isdn_tty_modem_result(6, info); + isdn_tty_modem_result(RESULT_NO_DIALTONE, info); } isdn_tty_modem_hup(info, 0); return 1; @@ -2937,6 +2953,7 @@ * For CONNECT-messages also switch to online-mode. * For RING-message handle auto-ATA if register 0 != 0 */ + static void isdn_tty_modem_result(int code, modem_info * info) { @@ -2949,14 +2966,13 @@ char s[ISDN_MSNLEN+10]; switch (code) { - case 2: - m->mdmreg[REG_RINGCNT]++; /* RING */ + case RESULT_RING: + m->mdmreg[REG_RINGCNT]++; if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA]) /* Automatically accept incoming call */ isdn_tty_cmd_ATA(info); break; - case 3: - /* NO CARRIER */ + case RESULT_NO_CARRIER: #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", (info->flags & ISDN_ASYNC_CLOSING), @@ -2991,13 +3007,13 @@ } #endif break; - case 1: - case 5: + case RESULT_CONNECT: + case RESULT_CONNECT64000: sprintf(info->last_cause, "0000"); if (!info->online) info->online = 2; break; - case 11: + case RESULT_VCON: #ifdef ISDN_DEBUG_MODEM_VOICE printk(KERN_DEBUG "res3: send VCON on ttyI%d\n", info->line); @@ -3006,27 +3022,30 @@ if (!info->online) info->online = 1; break; - } + } /* switch(code) */ + if (m->mdmreg[REG_RESP] & BIT_RESP) { /* Show results */ - isdn_tty_at_cout("\r\n", info); if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) { - /* Show numeric results */ - sprintf(s, "%d", code); + /* Show numeric results only */ + sprintf(s, "\r\n%d\r\n", code); isdn_tty_at_cout(s, info); } else { - if ((code == 2) && - (m->mdmreg[REG_RUNG] & BIT_RUNG) && - (m->mdmreg[REG_RINGCNT] > 1)) - return; - if ((code == 2) && (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE))) { - isdn_tty_at_cout("CALLER NUMBER: ", info); - isdn_tty_at_cout(dev->num[info->drv_index], info); - isdn_tty_at_cout("\r\n", info); + if (code == RESULT_RING) { + /* return if "show RUNG" and ringcounter>1 */ + if ((m->mdmreg[REG_RUNG] & BIT_RUNG) && + (m->mdmreg[REG_RINGCNT] > 1)) + return; + /* print CID, _before_ _every_ ring */ + if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) { + isdn_tty_at_cout("\r\nCALLER NUMBER: ", info); + isdn_tty_at_cout(dev->num[info->drv_index], info); + } } + isdn_tty_at_cout("\r\n", info); isdn_tty_at_cout(msg[code], info); switch (code) { - case 1: + case RESULT_CONNECT: switch (m->mdmreg[REG_L2PROT]) { case ISDN_PROTO_L2_MODEM: isdn_tty_at_cout(" ", info); @@ -3034,13 +3053,13 @@ break; } break; - case 2: + case RESULT_RING: /* Append CPN, if enabled */ if ((m->mdmreg[REG_CPN] & BIT_CPN)) { sprintf(s, "/%s", m->cpn); isdn_tty_at_cout(s, info); } - /* Print CID only once, _after_ 1.st RING */ + /* Print CID only once, _after_ 1st RING */ if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) && (m->mdmreg[REG_RINGCNT] == 1)) { isdn_tty_at_cout("\r\n", info); @@ -3048,10 +3067,10 @@ isdn_tty_at_cout(dev->num[info->drv_index], info); } break; - case 3: - case 6: - case 7: - case 8: + case RESULT_NO_CARRIER: + case RESULT_NO_DIALTONE: + case RESULT_BUSY: + case RESULT_NO_ANSWER: m->mdmreg[REG_RINGCNT] = 0; /* Append Cause-Message if enabled */ if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) { @@ -3059,7 +3078,7 @@ isdn_tty_at_cout(s, info); } break; - case 5: + case RESULT_CONNECT64000: /* Append Protocol to CONNECT message */ switch (m->mdmreg[REG_L2PROT]) { case ISDN_PROTO_L2_X75I: @@ -3087,10 +3106,10 @@ } break; } + isdn_tty_at_cout("\r\n", info); } - isdn_tty_at_cout("\r\n", info); } - if (code == 3) { + if (code == RESULT_NO_CARRIER) { save_flags(flags); cli(); if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { @@ -3108,6 +3127,7 @@ } } + /* * Display a modem-register-value. */ @@ -3160,8 +3180,8 @@ *q = 0; } -#define PARSE_ERROR { isdn_tty_modem_result(4, info); return; } -#define PARSE_ERROR1 { isdn_tty_modem_result(4, info); return 1; } +#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; } +#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; } static void isdn_tty_report(modem_info * info) @@ -3329,8 +3349,8 @@ /* &L -Set Numbers to listen on */ p[0]++; i = 0; - while ((strchr("0123456789,-*[]?;", *p[0])) && - (i < ISDN_LMSNLEN) && *p[0]) + while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) && + (i < ISDN_LMSNLEN)) m->lmsn[i++] = *p[0]++; m->lmsn[i] = '\0'; break; @@ -3381,7 +3401,7 @@ /* &V - Show registers */ p[0]++; isdn_tty_at_cout("\r\n", info); - for (i = 0; i < ISDN_MODEM_ANZREG; i++) { + for (i = 0; i < ISDN_MODEM_NUMREG; i++) { sprintf(rb, "S%02d=%03d%s", i, m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n"); isdn_tty_at_cout(rb, info); @@ -3486,7 +3506,7 @@ int bval; mreg = isdn_getnum(p); - if (mreg < 0 || mreg >= ISDN_MODEM_ANZREG) + if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG) PARSE_ERROR1; switch (*p[0]) { case '=': @@ -3589,7 +3609,7 @@ isdn_command(&cmd); isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); } else - isdn_tty_modem_result(8, info); + isdn_tty_modem_result(RESULT_NO_ANSWER, info); } #ifdef CONFIG_ISDN_AUDIO @@ -3779,7 +3799,7 @@ if (!m->vpar[0]) PARSE_ERROR1; if (info->online != 1) { - isdn_tty_modem_result(8, info); + isdn_tty_modem_result(RESULT_NO_ANSWER, info); return 1; } info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); @@ -3803,7 +3823,7 @@ printk(KERN_DEBUG "AT: +VRX\n"); #endif info->vonline |= 1; - isdn_tty_modem_result(1, info); + isdn_tty_modem_result(RESULT_CONNECT, info); return 0; break; case 4: @@ -3893,7 +3913,7 @@ if (!m->vpar[0]) PARSE_ERROR1; if (info->online != 1) { - isdn_tty_modem_result(8, info); + isdn_tty_modem_result(RESULT_NO_ANSWER, info); return 1; } info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); @@ -3913,7 +3933,7 @@ #endif m->lastDLE = 0; info->vonline |= 2; - isdn_tty_modem_result(1, info); + isdn_tty_modem_result(RESULT_CONNECT, info); return 0; break; case 7: @@ -3998,13 +4018,13 @@ if (info->msr & UART_MSR_DCD) PARSE_ERROR; if (info->msr & UART_MSR_RI) { - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); return; } isdn_tty_getdial(++p, ds, sizeof ds); p += strlen(p); if (!strlen(m->msn)) - isdn_tty_modem_result(10, info); + isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info); else if (strlen(ds)) isdn_tty_dial(ds, info, m); else @@ -4076,9 +4096,9 @@ p++; if (info->msr & UART_MSR_DCD) /* if B-Channel is up */ - isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? 1:5, info); + isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT:RESULT_CONNECT64000, info); else - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); return; case 'Q': /* Q - Turn Emulator messages on/off */ @@ -4171,7 +4191,7 @@ #ifdef CONFIG_ISDN_AUDIO if (!info->vonline) #endif - isdn_tty_modem_result(0, info); + isdn_tty_modem_result(RESULT_OK, info); } /* Need own toupper() because standard-toupper is not available @@ -4282,7 +4302,7 @@ ((jiffies - info->emu.lastplus) > PLUSWAIT2)) { info->emu.pluscount = 0; info->online = 0; - isdn_tty_modem_result(0, info); + isdn_tty_modem_result(RESULT_OK, info); } } } @@ -4304,7 +4324,7 @@ modem_info *info = &dev->mdm.info[i]; if (info->msr & UART_MSR_RI) { ton = 1; - isdn_tty_modem_result(2, info); + isdn_tty_modem_result(RESULT_RING, info); } } isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton); @@ -4346,7 +4366,7 @@ if (info->dialing) { if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) { info->dialing = 0; - isdn_tty_modem_result(3, info); + isdn_tty_modem_result(RESULT_NO_CARRIER, info); isdn_tty_modem_hup(info, 1); } else diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/isdn_tty.h linux/drivers/isdn/isdn_tty.h --- v2.3.47/linux/drivers/isdn/isdn_tty.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/isdn_tty.h Sat Feb 26 20:20:13 2000 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.h,v 1.18 2000/01/20 19:55:33 keil Exp $ +/* $Id: isdn_tty.h,v 1.19 2000/02/16 14:59:33 paul Exp $ * header for Linux ISDN subsystem, tty related functions (linklevel). * @@ -20,6 +20,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.19 2000/02/16 14:59:33 paul + * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers; + * used defines for result codes; + * fixed RING ... RUNG problem (no empty lines in between). + * * Revision 1.18 2000/01/20 19:55:33 keil * Add FAX Class 1 support * @@ -110,7 +115,7 @@ * Definition of some special Registers of AT-Emulator */ #define REG_RINGATA 0 -#define REG_RINGCNT 1 +#define REG_RINGCNT 1 /* ring counter register */ #define REG_ESC 2 #define REG_CR 3 #define REG_LF 4 @@ -118,10 +123,10 @@ #define REG_WAITC 7 -#define REG_RESP 12 -#define BIT_RESP 1 -#define REG_RESPNUM 12 -#define BIT_RESPNUM 2 +#define REG_RESP 12 /* show response messages register */ +#define BIT_RESP 1 /* show response messages bit */ +#define REG_RESPNUM 12 /* show numeric responses register */ +#define BIT_RESPNUM 2 /* show numeric responses bit */ #define REG_ECHO 12 #define BIT_ECHO 4 #define REG_DCD 12 @@ -144,8 +149,8 @@ #define BIT_RESPXT 8 #define REG_CIDONCE 13 #define BIT_CIDONCE 16 -#define REG_RUNG 13 -#define BIT_RUNG 64 +#define REG_RUNG 13 /* show RUNG message register */ +#define BIT_RUNG 64 /* show RUNG message bit */ #define REG_DISPLAY 13 #define BIT_DISPLAY 128 @@ -162,6 +167,21 @@ #define REG_CPN 23 #define BIT_CPN 1 #define BIT_CPNFCON 2 + +/* defines for result codes */ +#define RESULT_OK 0 +#define RESULT_CONNECT 1 +#define RESULT_RING 2 +#define RESULT_NO_CARRIER 3 +#define RESULT_ERROR 4 +#define RESULT_CONNECT64000 5 +#define RESULT_NO_DIALTONE 6 +#define RESULT_BUSY 7 +#define RESULT_NO_ANSWER 8 +#define RESULT_RINGING 9 +#define RESULT_NO_MSN_EAZ 10 +#define RESULT_VCON 11 +#define RESULT_RUNG 12 #define TTY_IS_FCLASS1(info) \ ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \ diff -u --recursive --new-file v2.3.47/linux/drivers/isdn/sc/debug.h linux/drivers/isdn/sc/debug.h --- v2.3.47/linux/drivers/isdn/sc/debug.h Tue Nov 23 22:42:20 1999 +++ linux/drivers/isdn/sc/debug.h Sat Feb 26 20:20:13 2000 @@ -1,5 +1,5 @@ /* - * $Id: debug.h,v 1.1 1996/11/07 13:07:42 fritz Exp $ + * $Id: debug.h,v 1.2 2000/02/26 01:00:53 keil Exp $ * Copyright (C) 1996 SpellCaster Telecommunications Inc. * * This program is free software; you can redistribute it and/or modify diff -u --recursive --new-file v2.3.47/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.3.47/linux/drivers/net/3c505.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/3c505.c Mon Feb 21 11:23:42 2000 @@ -361,8 +361,7 @@ static inline void prime_rx(struct net_device *dev) { elp_device *adapter = dev->priv; - while (adapter->rx_active < ELP_RX_PCBS && - netif_running(dev->state)) { + while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) { if (!start_receive(dev, &adapter->itx_pcb)) break; } diff -u --recursive --new-file v2.3.47/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.3.47/linux/drivers/net/8139too.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/8139too.c Sat Feb 26 20:22:08 2000 @@ -87,7 +87,7 @@ #include -#define RTL8139_VERSION "0.9.3" +#define RTL8139_VERSION "0.9.4" #define RTL8139_MODULE_NAME "8139too" #define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION #define PFX RTL8139_MODULE_NAME ": " @@ -101,8 +101,8 @@ #define DPRINTK(fmt, args...) #endif -#define RTL8139_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ -#if RTL8139_NDEBUG +#undef RTL8139_NDEBUG /* define to 1 to disable lightweight runtime checks */ +#ifdef RTL8139_NDEBUG #define assert(expr) #else #define assert(expr) \ @@ -144,6 +144,7 @@ #define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ #define TX_DMA_BURST 4 /* Calculate as 16< 0x80 ? */ + spinlock_t lock; }; MODULE_AUTHOR ("Jeff Garzik "); @@ -374,6 +392,8 @@ static struct net_device_stats *rtl8139_get_stats (struct net_device *dev); static inline u32 ether_crc (int length, unsigned char *data); static void rtl8139_set_rx_mode (struct net_device *dev); +static void rtl8139_hw_start (struct net_device *dev); + /* write MMIO register, with flush */ /* Flush avoids rtl8139 bug w/ posted MMIO writes */ @@ -409,30 +429,17 @@ TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8139_rx_config = - (RX_FIFO_THRESH << 13) | - (RX_BUF_LEN_IDX << 11) | + (RX_FIFO_THRESH << 13) | (RxCfgRcv32K) | (RX_DMA_BURST << 8); -static const char * __devinit rtl8139_name_from_chip (chip_t chip) -{ - int i; - - for (i = 0; i < arraysize (chip_info); i++) - if (chip == chip_info[i].chip) - return chip_info[i].name; - - return "unknown"; -} - - static int __devinit rtl8139_init_pci (struct pci_dev *pdev, void **ioaddr_out) { void *ioaddr = NULL; u8 tmp8; int rc; - u32 pio_start, pio_end, pio_flags; - u32 mmio_start, mmio_end, mmio_flags; + u32 pio_start, pio_end, pio_flags, pio_len; + u32 mmio_start, mmio_end, mmio_flags, mmio_len; DPRINTK ("ENTER\n"); @@ -444,48 +451,67 @@ pio_start = pci_resource_start (pdev, 0); pio_end = pci_resource_end (pdev, 0); pio_flags = pci_resource_flags (pdev, 0); + pio_len = pci_resource_len (pdev, 0); mmio_start = pci_resource_start (pdev, 1); mmio_end = pci_resource_end (pdev, 1); mmio_flags = pci_resource_flags (pdev, 1); + mmio_len = pci_resource_len (pdev, 1); /* make sure PCI base addr 0 is PIO */ - if (pio_start == 0 || pio_end <= pio_start || - (!(pio_flags & IORESOURCE_IO))) { - printk (KERN_ERR PFX "no PIO resource, aborting\n"); - return -ENODEV; + if (!(pio_flags & IORESOURCE_IO)) { + printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n"); + rc = -ENODEV; + goto err_out; } /* make sure PCI base addr 1 is MMIO */ - if (mmio_start == 0 || mmio_end <= mmio_start || - (!(mmio_flags & IORESOURCE_MEM))) { - printk (KERN_ERR PFX "no MMIO resource, aborting\n"); - return -ENODEV; + if (!(mmio_flags & IORESOURCE_MEM)) { + printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); + rc = -ENODEV; + goto err_out; + } + + /* check for weird/broken PCI region reporting */ + if ((pio_len != mmio_len) || + (pio_len < RTL_MIN_IO_SIZE) || + (mmio_len < RTL_MIN_IO_SIZE)) { + printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); + rc = -ENODEV; + goto err_out; } /* make sure our PIO region in PCI space is available */ - if (!request_region (pio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) { + if (!request_region (pio_start, pio_len, RTL8139_MODULE_NAME)) { printk (KERN_ERR PFX "no I/O resource available, aborting\n"); - return -EBUSY; + rc = -EBUSY; + goto err_out; } /* make sure our MMIO region in PCI space is available */ - if (!request_mem_region (mmio_start, RTL_IO_SIZE, RTL8139_MODULE_NAME)) { - release_region (pio_start, RTL_IO_SIZE); + if (!request_mem_region (mmio_start, mmio_len, RTL8139_MODULE_NAME)) { printk (KERN_ERR PFX "no mem resource available, aborting\n"); - return -EBUSY; + rc = -EBUSY; + goto err_out_free_pio; } /* enable device (incl. PCI PM wakeup), and bus-mastering */ - pci_enable_device (pdev); + rc = pci_enable_device (pdev); + if (rc) { + printk (KERN_ERR PFX "cannot enable PCI device (bus %d, " + "devfn %d), aborting\n", + pdev->bus->number, pdev->devfn); + goto err_out_free_mmio; + } + pci_set_master (pdev); /* ioremap MMIO region */ - ioaddr = ioremap (mmio_start, RTL_IO_SIZE); + ioaddr = ioremap (mmio_start, mmio_len); if (ioaddr == NULL) { printk (KERN_ERR PFX "cannot remap MMIO, aborting\n"); rc = -EIO; - goto err_out; + goto err_out_free_mmio; } /* Bring the chip out of low-power mode. */ @@ -496,12 +522,12 @@ if ((tmp8 & Cfg1_PIO) == 0) { printk (KERN_ERR PFX "PIO not enabled, Cfg1=%02X, aborting\n", tmp8); rc = -EIO; - goto err_out; + goto err_out_iounmap; } if ((tmp8 & Cfg1_MMIO) == 0) { printk (KERN_ERR PFX "MMIO not enabled, Cfg1=%02X, aborting\n", tmp8); rc = -EIO; - goto err_out; + goto err_out_iounmap; } /* sanity checks -- ensure PIO and MMIO registers agree */ @@ -514,28 +540,43 @@ *ioaddr_out = ioaddr; return 0; +err_out_iounmap: + assert (ioaddr > 0); + iounmap (ioaddr); +err_out_free_mmio: + release_mem_region (mmio_start, mmio_len); +err_out_free_pio: + release_region (pio_start, pio_len); err_out: - if (ioaddr) - iounmap (ioaddr); - release_region (pio_start, RTL_IO_SIZE); - release_mem_region (mmio_start, RTL_IO_SIZE); DPRINTK ("EXIT, returning %d\n", rc); return rc; } -static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +static int __devinit rtl8139_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) { struct net_device *dev; struct rtl8139_private *tp; int i, addr_len, option = -1; void *ioaddr = NULL; +#ifndef RTL8139_NDEBUG + static int printed_version = 0; +#endif /* RTL8139_NDEBUG */ + DPRINTK ("ENTER\n"); assert (pdev != NULL); assert (ent != NULL); - + +#ifndef RTL8139_NDEBUG + if (!printed_version) { + printk (KERN_INFO RTL8139_DRIVER_NAME " loaded\n"); + printed_version = 1; + } +#endif /* RTL8139_NDEBUG */ + i = rtl8139_init_pci (pdev, &ioaddr); if (i < 0) { DPRINTK ("EXIT, returning %d\n", i); @@ -571,31 +612,34 @@ dev->irq = pdev->irq; dev->base_addr = pci_resource_start (pdev, 1); + /* dev->priv/tp zeroed in init_etherdev */ dev->priv = tp = (void *) (((long)dev->priv + PRIV_ALIGN) & ~PRIV_ALIGN); - printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", - dev->name, rtl8139_name_from_chip(ent->driver_data), - dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); - - /* tp zeroed in init_etherdev */ tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | RTL8139_CAPS; tp->pci_dev = pdev; tp->chip = ent->driver_data; tp->mmio_addr = ioaddr; + tp->extended_regs = + (pci_resource_len (pdev, 0) == RTL8139B_IO_SIZE) ? 1 : 0; tp->lock = SPIN_LOCK_UNLOCKED; PCI_SET_DRIVER_DATA (pdev, dev); tp->phys[0] = 32; + printk (KERN_INFO "%s: %s at 0x%lx, IRQ %d,%s " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + dev->name, chip_info[ent->driver_data].name, + dev->base_addr, dev->irq, + tp->extended_regs ? " 8139B regs," : "", + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + /* Put the chip into low-power mode. */ - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, 0x03); /* Enable PM & PCI VPD */ RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ @@ -635,8 +679,10 @@ unregister_netdev (dev); iounmap (np->mmio_addr); - release_region (pci_resource_start (pdev, 0), RTL_IO_SIZE); - release_mem_region (pci_resource_start (pdev, 1), RTL_IO_SIZE); + release_region (pci_resource_start (pdev, 0), + pci_resource_len (pdev, 0)); + release_mem_region (pci_resource_start (pdev, 1), + pci_resource_len (pdev, 1)); #ifndef RTL8139_NDEBUG /* poison memory before freeing */ @@ -644,7 +690,7 @@ sizeof (struct net_device) + sizeof (struct rtl8139_private) + PRIV_ALIGN); -#endif +#endif /* RTL8139_NDEBUG */ kfree (dev); @@ -851,16 +897,14 @@ static int rtl8139_open (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; +#ifdef RTL8139_DEBUG void *ioaddr = tp->mmio_addr; - int i; +#endif DPRINTK ("ENTER\n"); MOD_INC_USE_COUNT; - /* Soft reset the chip. */ - RTL_W8 (ChipCmd, CmdReset); - if (request_irq (dev->irq, &rtl8139_interrupt, SA_SHIRQ, dev->name, dev)) { DPRINTK ("EXIT, returning -EBUSY\n"); MOD_DEC_USE_COUNT; @@ -891,44 +935,7 @@ tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; - /* Check that the chip has finished the reset. */ - for (i = 1000; i > 0; i--) - if ((RTL_R8 (ChipCmd) & CmdReset) == 0) - break; - - RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); - RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); - - /* Must enable Tx/Rx before setting transfer thresholds! */ - RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); - RTL_W32 (RxConfig, rtl8139_rx_config); - RTL_W32 (TxConfig, (TX_DMA_BURST << 8) | 0x00000000); - - /* Reset N-Way to chipset defaults */ - RTL_W16 (BasicModeCtrl, (1<<15)|(1<<12)|(1<<9)); - for (i = 1000; i > 0; i--) - if ((RTL_R8 (BasicModeCtrl) & (1<<15)) == 0) - break; - - /* Set N-Way to sane defaults */ - RTL_W16 (FIFOTMS, 0x0000); - RTL_W16 (NWayAdvert, (1<<13)|(1<<8)|(1<<7)|(1<<6)|(1<<5)|0x1); - RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8)); - - RTL_W8 (Cfg9346, 0xC0); - RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); - - RTL_W32 (RxBuf, tp->rx_ring_dma); - - /* Start the chip's Tx and Rx process. */ - RTL_W32 (RxMissed, 0); - rtl8139_set_rx_mode (dev); - - RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); - - /* Enable all known interrupts by setting the interrupt mask. */ - RTL_W16 (IntrMask, rtl8139_intr_mask); + rtl8139_hw_start (dev); DPRINTK ("%s: rtl8139_open() ioaddr %#lx IRQ %d" " GP Pins %2.2x %s-duplex.\n", @@ -944,23 +951,26 @@ tp->timer.function = &rtl8139_timer; add_timer (&tp->timer); - netif_start_queue (dev); - DPRINTK ("EXIT, returning 0\n"); return 0; } + /* Start the hardware at open or resume. */ static void rtl8139_hw_start (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int i; + unsigned long flags; DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&tp->lock, flags); /* Soft reset the chip. */ RTL_W8 (ChipCmd, CmdReset); + /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((RTL_R8 (ChipCmd) & CmdReset) == 0) @@ -970,8 +980,9 @@ RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0))); RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4))); - /* Hmmm, do these belong here? */ - RTL_W8 (Cfg9346, 0x00); + /* unlock Config[01234] and BMCR register writes */ + RTL_W8 (Cfg9346, Cfg9346_Unlock); + tp->cur_rx = 0; /* Must enable Tx/Rx before setting transfer thresholds! */ @@ -993,19 +1004,30 @@ RTL_W16 (BasicModeCtrl, (1<<13)|(1<<12)|(1<<9)|(1<<8)); /* check_duplex() here. */ - RTL_W8 (Cfg9346, 0xC0); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); + + /* lock Config[01234] and BMCR register writes */ + RTL_W8 (Cfg9346, Cfg9346_Lock); RTL_W32 (RxBuf, tp->rx_ring_dma); + /* Start the chip's Tx and Rx process. */ RTL_W32 (RxMissed, 0); + + /* release lock cuz set_rx_mode wants it */ + spin_unlock_irqrestore (&tp->lock, flags); rtl8139_set_rx_mode (dev); + spin_lock_irqsave (&tp->lock, flags); + RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb); + /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16 (IntrMask, rtl8139_intr_mask); - netif_start_queue (dev); + if (netif_queue_stopped (dev)) + netif_start_queue (dev); + + spin_unlock_irqrestore (&tp->lock, flags); DPRINTK ("EXIT\n"); } @@ -1111,9 +1133,14 @@ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int next_tick = 60 * HZ; - int mii_reg5 = mdio_read (dev, tp->phys[0], 5); + int mii_reg5; + unsigned long flags; DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&tp->lock, flags); + + mii_reg5 = mdio_read (dev, tp->phys[0], 5); if (!tp->duplex_lock && mii_reg5 != 0xffff) { int duplex = (mii_reg5 & 0x0100) @@ -1125,9 +1152,9 @@ " partner ability of %4.4x.\n", dev->name, tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5); - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); + RTL_W8 (Cfg9346, Cfg9346_Lock); } } @@ -1144,6 +1171,8 @@ dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); + spin_unlock_irqrestore (&tp->lock, flags); + tp->timer.expires = jiffies + next_tick; add_timer (&tp->timer); @@ -1156,10 +1185,11 @@ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int mii_reg, i; + unsigned long flags; DPRINTK ("ENTER\n"); - netif_stop_queue (dev); + spin_lock_irqsave (&tp->lock, flags); DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, @@ -1201,6 +1231,8 @@ } } + spin_unlock_irqrestore (&tp->lock, flags); + rtl8139_hw_start (dev); DPRINTK ("EXIT\n"); @@ -1227,6 +1259,7 @@ DPRINTK ("EXIT\n"); } + static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; @@ -1236,13 +1269,11 @@ DPRINTK ("ENTER\n"); - netif_stop_queue (dev); + spin_lock_irqsave (&tp->lock, flags); /* Calculate the next Tx descriptor entry. */ entry = tp->cur_tx % NUM_TX_DESC; - spin_lock_irqsave (&tp->lock, flags); - tp->tx_info[entry].skb = skb; if ((long) skb->data & 3) { /* Must use alignment buffer. */ tp->tx_info[entry].mapping = 0; @@ -1263,12 +1294,12 @@ tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); dev->trans_start = jiffies; - if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) /* Typical path */ - netif_start_queue (dev); + if (++tp->cur_tx - tp->dirty_tx >= NUM_TX_DESC) + netif_stop_queue (dev); spin_unlock_irqrestore (&tp->lock, flags); - - DPRINTK ("%s: Queued Tx packet at %p size %lu to slot %d.\n", + + DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n", dev->name, skb->data, skb->len, entry); DPRINTK ("EXIT\n"); @@ -1277,16 +1308,16 @@ static inline void rtl8139_tx_interrupt (struct net_device *dev, - struct rtl8139_private *tp) + struct rtl8139_private *tp, + void *ioaddr) { - void *ioaddr; unsigned int dirty_tx; assert (dev != NULL); assert (tp != NULL); - + assert (ioaddr != NULL); + dirty_tx = tp->dirty_tx; - ioaddr = tp->mmio_addr; while (tp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % NUM_TX_DESC; @@ -1338,8 +1369,6 @@ dirty_tx++; if (tp->cur_tx - dirty_tx < NUM_TX_DESC) netif_wake_queue (dev); - else - netif_stop_queue (dev); } #ifndef RTL8139_NDEBUG @@ -1349,7 +1378,7 @@ dev->name, dirty_tx, tp->cur_tx); dirty_tx += NUM_TX_DESC; } -#endif +#endif /* RTL8139_NDEBUG */ tp->dirty_tx = dirty_tx; } @@ -1358,11 +1387,18 @@ /* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the field alignments and semantics. */ static inline void rtl8139_rx_interrupt (struct net_device *dev, - struct rtl8139_private *tp) + struct rtl8139_private *tp, + void *ioaddr) { - void *ioaddr = tp->mmio_addr; - unsigned char *rx_ring = tp->rx_ring; - u16 cur_rx = tp->cur_rx; + unsigned char *rx_ring; + u16 cur_rx; + + assert (dev != NULL); + assert (tp != NULL); + assert (ioaddr != NULL); + + rx_ring = tp->rx_ring; + cur_rx = tp->cur_rx; DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, @@ -1376,15 +1412,17 @@ le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); int rx_size = rx_status >> 16; -#ifdef RTL8139_DEBUG - int i; DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," " cur %4.4x.\n", dev->name, rx_status, rx_size, cur_rx); +#if RTL8139_DEBUG > 2 + { + int i; DPRINTK ("%s: Frame contents ", dev->name); for (i = 0; i < 70; i++) printk (" %2.2x", rx_ring[ring_offset + i]); printk (".\n"); + } #endif /* E. Gill */ @@ -1490,23 +1528,16 @@ static inline int rtl8139_weird_interrupt (struct net_device *dev, struct rtl8139_private *tp, + void *ioaddr, int status, int link_changed) { - void *ioaddr; - DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", dev->name, status); assert (dev != NULL); assert (tp != NULL); - - ioaddr = tp->mmio_addr; - - if (status == 0xffffffff) { - printk (KERN_WARNING PFX "abnormal interrupt, card ejected? (ok to ignore)\n"); - return -1; - } - + assert (ioaddr != NULL); + /* Update the error count. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); @@ -1519,9 +1550,9 @@ || tp->duplex_lock; if (tp->full_duplex != duplex) { tp->full_duplex = duplex; - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20); - RTL_W8 (Cfg9346, 0x00); + RTL_W8 (Cfg9346, Cfg9346_Lock); } status &= ~RxUnderrun; } @@ -1559,15 +1590,20 @@ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; int boguscnt = max_interrupt_work; void *ioaddr = tp->mmio_addr; - int link_changed = 0; /* Grrr, avoid bogus "uninitialized" warning */ - - spin_lock_irq (&tp->lock); + int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ + spin_lock (&tp->lock); + /* disable interrupt generation while handling this interrupt */ RTL_W16 (IntrMask, 0x0000); do { - int status = RTL_R16 (IntrStatus); + status = RTL_R16 (IntrStatus); + + /* h/w no longer present (hotplug?) or major error, bail */ + if (status == 0xFFFFFFFF) + break; + /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ if (status & RxUnderrun) @@ -1606,42 +1642,45 @@ /* Check uncommon events with one test. */ if (status & (PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | RxErr)) - if (rtl8139_weird_interrupt (dev, tp, status, - link_changed) == -1) - break; + rtl8139_weird_interrupt (dev, tp, ioaddr, + status, link_changed); if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) /* Rx interrupt */ - rtl8139_rx_interrupt (dev, tp); + rtl8139_rx_interrupt (dev, tp, ioaddr); if (status & (TxOK | TxErr)) - rtl8139_tx_interrupt (dev, tp); + rtl8139_tx_interrupt (dev, tp, ioaddr); - if (--boguscnt < 0) { - printk (KERN_WARNING - "%s: Too much work at interrupt, " - "IntrStatus=0x%4.4x.\n", dev->name, - status); - /* Clear all interrupt sources. */ - RTL_W16 (IntrStatus, 0xffff); - break; - } - } while (1); + boguscnt--; + } while (boguscnt > 0); + + if (boguscnt <= 0) { + printk (KERN_WARNING + "%s: Too much work at interrupt, " + "IntrStatus=0x%4.4x.\n", dev->name, + status); + + /* Clear all interrupt sources. */ + RTL_W16 (IntrStatus, 0xffff); + } /* Enable all known interrupts by setting the interrupt mask. */ RTL_W16 (IntrMask, rtl8139_intr_mask); - spin_unlock_irq (&tp->lock); - + spin_unlock (&tp->lock); + DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", - dev->name, RTL_R16 (IntrStatus)); + dev->name, RTL_R16 (IntrStatus)); } + static int rtl8139_close (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int i; + unsigned long flags; DPRINTK ("ENTER\n"); @@ -1650,6 +1689,8 @@ DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); + spin_lock_irqsave (&tp->lock, flags); + /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); @@ -1660,7 +1701,13 @@ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + spin_unlock_irqrestore (&tp->lock, flags); + del_timer (&tp->timer); + + /* snooze for a small bit */ + if (current->need_resched) + schedule (); free_irq (dev->irq, dev); @@ -1685,7 +1732,7 @@ tp->tx_bufs = NULL; /* Green! Put the chip in low-power mode. */ - RTL_W8 (Cfg9346, 0xC0); + RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, 0x03); RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ @@ -1695,10 +1742,13 @@ return 0; } + static int mii_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; u16 *data = (u16 *) & rq->ifr_data; + unsigned long flags; + int rc = 0; DPRINTK ("ENTER\n"); @@ -1706,24 +1756,34 @@ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ data[0] = tp->phys[0] & 0x3f; /* Fall Through */ + case SIOCDEVPRIVATE + 1: /* Read the specified MII register. */ + spin_lock_irqsave (&tp->lock, flags); data[3] = mdio_read (dev, data[0], data[1] & 0x1f); - DPRINTK ("EXIT\n"); - return 0; + spin_unlock_irqrestore (&tp->lock, flags); + break; + case SIOCDEVPRIVATE + 2: /* Write the specified MII register */ - if (!capable (CAP_NET_ADMIN)) - return -EPERM; + if (!capable (CAP_NET_ADMIN)) { + rc = -EPERM; + break; + } + + spin_lock_irqsave (&tp->lock, flags); mdio_write (dev, data[0], data[1] & 0x1f, data[2]); - DPRINTK ("EXIT\n"); - return 0; + spin_unlock_irqrestore (&tp->lock, flags); + break; + default: - DPRINTK ("EXIT\n"); - return -EOPNOTSUPP; + rc = -EOPNOTSUPP; + break; } - DPRINTK ("EXIT\n"); + DPRINTK ("EXIT, returning %d\n", rc); + return rc; } + static struct net_device_stats *rtl8139_get_stats (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; @@ -1734,8 +1794,14 @@ assert (tp != NULL); if (netif_running(dev)) { + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + + spin_unlock_irqrestore (&tp->lock, flags); } DPRINTK ("EXIT\n"); @@ -1765,12 +1831,14 @@ return crc; } + static void rtl8139_set_rx_mode (struct net_device *dev) { struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; + unsigned long flags; DPRINTK ("ENTER\n"); @@ -1803,11 +1871,19 @@ dmi_addr) >> 26, mc_filter); } + + /* if called from irq handler, lock already acquired */ + if (!in_irq ()) + spin_lock_irqsave (&tp->lock, flags); + /* We can safely update without stopping the chip. */ RTL_W32 (RxConfig, rtl8139_rx_config | rx_mode); RTL_W32_F (MAR0 + 0, mc_filter[0]); RTL_W32_F (MAR0 + 4, mc_filter[1]); + if (!in_irq ()) + spin_unlock_irqrestore (&tp->lock, flags); + DPRINTK ("EXIT\n"); } @@ -1817,9 +1893,12 @@ struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; + unsigned long flags; - netif_stop_queue (dev); + netif_device_detach (dev); + spin_lock_irqsave (&tp->lock, flags); + /* Disable interrupts, stop Tx and Rx. */ RTL_W16 (IntrMask, 0x0000); RTL_W8 (ChipCmd, 0x00); @@ -1827,6 +1906,8 @@ /* Update the error counts. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); + + spin_unlock_irqrestore (&tp->lock, flags); } @@ -1834,7 +1915,8 @@ { struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); - rtl8139_hw_start(dev); + netif_device_attach (dev); + rtl8139_hw_start (dev); } @@ -1850,22 +1932,7 @@ static int __init rtl8139_init_module (void) { - int rc; - - DPRINTK ("ENTER\n"); - - rc = pci_register_driver (&rtl8139_pci_driver); - - if (rc > 0) { - printk (KERN_INFO RTL8139_DRIVER_NAME - " loaded (%d device%s registered)\n", - rc, rc > 1 ? "s" : ""); - } else { - pci_unregister_driver (&rtl8139_pci_driver); - } - - DPRINTK ("EXIT\n"); - return rc > 0 ? 0 : -ENODEV; + return pci_module_init (&rtl8139_pci_driver); } diff -u --recursive --new-file v2.3.47/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.47/linux/drivers/net/Config.in Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/Config.in Thu Feb 24 22:49:19 2000 @@ -46,6 +46,9 @@ if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then tristate ' MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC fi + if [ "$CONFIG_SGI_IP27" = "y" ]; then + bool ' SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH + fi bool ' 3COM cards' CONFIG_NET_VENDOR_3COM if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then tristate ' 3c501 support' CONFIG_EL1 @@ -251,9 +254,7 @@ bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO if [ "$CONFIG_NET_RADIO" = "y" ]; then dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET - if [ "$CONFIG_OBSOLETE" = "y" ]; then - tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN - fi + tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN tristate ' Aironet 4500/4800 series adapters' CONFIG_AIRONET4500 dep_tristate ' Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500 diff -u --recursive --new-file v2.3.47/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.47/linux/drivers/net/Makefile Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/Makefile Thu Feb 24 22:49:19 2000 @@ -18,7 +18,7 @@ MOD_SUB_DIRS := MOD_IN_SUB_DIRS := ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \ - arcnet skfp + arcnet skfp tulip O_TARGET := net.o MOD_LIST_NAME := NET_MODULES @@ -38,6 +38,15 @@ endif endif +ifeq ($(CONFIG_TULIP),y) + SUB_DIRS += tulip + obj-y += tulip/tulip.o +else + ifeq ($(CONFIG_TULIP),m) + MOD_SUB_DIRS += tulip + endif +endif + ifeq ($(CONFIG_IRDA),y) SUB_DIRS += irda MOD_IN_SUB_DIRS += irda @@ -122,7 +131,6 @@ obj-$(CONFIG_PCNET32) += pcnet32.o obj-$(CONFIG_EEPRO100) += eepro100.o obj-$(CONFIG_TLAN) += tlan.o -obj-$(CONFIG_TULIP) += tulip.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_SIS900) += sis900.o obj-$(CONFIG_DM9102) += dmfe.o @@ -261,6 +269,7 @@ obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o obj-$(CONFIG_EQUALIZER) += eql.o obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o +obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_BAGETLANCE) += bagetlance.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_ATARILANCE) += atarilance.o diff -u --recursive --new-file v2.3.47/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.3.47/linux/drivers/net/Space.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/Space.c Thu Feb 24 22:49:19 2000 @@ -79,6 +79,7 @@ extern int ni52_probe(struct net_device *); extern int ni65_probe(struct net_device *); extern int sonic_probe(struct net_device *); +extern int ioc3_probe(struct net_device *); extern int SK_init(struct net_device *); extern int seeq8005_probe(struct net_device *); extern int smc_init( struct net_device * ); @@ -384,6 +385,9 @@ struct devprobe mips_probes[] __initdata = { #ifdef CONFIG_MIPS_JAZZ_SONIC {sonic_probe, 0}, +#endif +#ifdef CONFIG_SGI_IOC3_ETH + {ioc3_probe, 0}, #endif #ifdef CONFIG_DECLANCE /* DECstation on-board controller */ {dec_lance_probe, 0}, /* and maybe TURBOchannel option boards */ diff -u --recursive --new-file v2.3.47/linux/drivers/net/bagetlance.c linux/drivers/net/bagetlance.c --- v2.3.47/linux/drivers/net/bagetlance.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/bagetlance.c Thu Feb 24 22:49:19 2000 @@ -1,4 +1,4 @@ -/* $Id$ +/* $Id: bagetlance.c,v 1.2 1999/10/09 00:01:21 ralf Exp $ * vmelance.c: Ethernet driver for VME Lance cards on Baget/MIPS * This code stealed and adopted from linux/drivers/net/atarilance.c * See that for author info diff -u --recursive --new-file v2.3.47/linux/drivers/net/declance.c linux/drivers/net/declance.c --- v2.3.47/linux/drivers/net/declance.c Tue Aug 31 17:29:14 1999 +++ linux/drivers/net/declance.c Thu Feb 24 22:49:19 2000 @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -301,6 +302,7 @@ static inline void writereg(volatile unsigned short *regptr, short value) { *regptr = value; + wbflush(); } /* Load the CSR registers */ @@ -380,6 +382,7 @@ } } + wbflush(); } void cp_from_buf(void *to, unsigned char *from, int len) @@ -515,6 +518,7 @@ if (i < 3 && ZERO) printk("%d: 0x%8.8x(0x%8.8x)\n", i, leptr, (int) lp->rx_buf_ptr_cpu[i]); } + wbflush(); } static int init_restart_lance(struct lance_private *lp) @@ -752,6 +756,7 @@ * re-enable LANCE DMA */ *(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16); + wbflush(); } writereg(&ll->rdp, LE_C0_STOP); @@ -1071,6 +1076,7 @@ lp->dma_ptr_reg = (unsigned long *) (system_base + IOCTL + LANCE_DMA_P); *(lp->dma_ptr_reg) = PHYSADDR(dev->mem_start) << 3; *(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16); + wbflush(); break; case PMAD_LANCE: diff -u --recursive --new-file v2.3.47/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.3.47/linux/drivers/net/eepro100.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/eepro100.c Sat Feb 26 20:22:09 2000 @@ -536,6 +536,9 @@ static int did_version = 0; /* Already printed version info. */ + if (speedo_debug > 0 && did_version++ == 0) + printk(version); + #ifdef USE_IO ioaddr = pci_resource_start (pdev, 0); #else @@ -569,9 +572,6 @@ } #endif - if (speedo_debug > 0 && did_version++ == 0) - printk(version); - tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats), &tx_ring_dma); if (!tx_ring) { @@ -604,7 +604,11 @@ acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; } - pci_enable_device (pdev); + if (pci_enable_device (pdev)) { + printk(KERN_ERR PFX "Could not enable PCI device\n"); + goto err_out_free_netdev; + } + pci_set_master (pdev); /* Read the station address EEPROM before doing the reset. @@ -732,11 +736,12 @@ /* Return the chip to its original power state. */ pci_set_power_state (pdev, acpi_idle_state); + pdev->driver_data = dev; + dev->base_addr = ioaddr; dev->irq = irq; sp = dev->priv; - memset(sp, 0, sizeof(*sp)); sp->pdev = pdev; sp->acpi_pwr = acpi_idle_state; @@ -872,6 +877,8 @@ if (speedo_debug > 1) printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq); + MOD_INC_USE_COUNT; + pci_set_power_state(sp->pdev, 0); /* Set up the Tx queue early.. */ @@ -882,12 +889,13 @@ spin_lock_init(&sp->lock); /* .. we can safely take handler calls during init. */ - if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) + if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; return -EBUSY; - - MOD_INC_USE_COUNT; + } dev->if_port = sp->default_port; + #if 0 /* With some transceivers we must retrigger negotiation to reset power-up errors. */ @@ -1174,8 +1182,6 @@ long ioaddr = dev->base_addr; int entry; - netif_stop_queue (dev); - /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ @@ -1216,16 +1222,15 @@ } if (sp->cur_tx - sp->dirty_tx >= TX_QUEUE_LIMIT) { sp->tx_full = 1; + netif_stop_queue (dev); } spin_unlock_irqrestore(&sp->lock, flags); } + wait_for_cmd_done(ioaddr + SCBCmd); outw(CUResume, ioaddr + SCBCmd); dev->trans_start = jiffies; - if (! sp->tx_full) - netif_start_queue (dev); - return 0; } @@ -1328,22 +1333,18 @@ && sp->cur_tx - dirty_tx < TX_QUEUE_LIMIT - 1) { /* The ring is no longer full, clear tbusy. */ sp->tx_full = 0; - } - - if (sp->tx_full) - netif_stop_queue (dev); - else netif_wake_queue (dev); + } } - if (--boguscnt < 0) { - printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - outl(0xfc00, ioaddr + SCBStatus); - break; - } - } while (1); + } while (--boguscnt > 0); + + if (boguscnt <= 0) { + printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", + dev->name, status); + /* Clear all interrupt sources. */ + outl(0xfc00, ioaddr + SCBStatus); + } if (speedo_debug > 3) printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", @@ -1502,8 +1503,8 @@ /* Clear the Tx descriptors. */ if (skb) { pci_unmap_single(sp->pdev, - le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), - skb->len, PCI_DMA_TODEVICE); + le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), + skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); } } @@ -1811,8 +1812,6 @@ iounmap ((char *) dev->base_addr); #endif - pci_set_power_state (pdev, sp->acpi_pwr); - pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats), sp->tx_ring, sp->tx_ring_dma); @@ -1841,23 +1840,10 @@ static int __init eepro100_init_module(void) { - int cards_found; - if (debug >= 0) speedo_debug = debug; - /* Always emit the version message. */ - if (speedo_debug) - printk(KERN_INFO "%s", version); - - cards_found = pci_register_driver (&eepro100_driver); - if (cards_found <= 0) { - printk(KERN_INFO PFX "No cards found, driver not installed.\n"); - pci_unregister_driver (&eepro100_driver); - return -ENODEV; - } - - return 0; + return pci_module_init (&eepro100_driver); } diff -u --recursive --new-file v2.3.47/linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c --- v2.3.47/linux/drivers/net/hamradio/6pack.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/hamradio/6pack.c Tue Feb 22 10:20:11 2000 @@ -752,8 +752,8 @@ * VSV = if dev->start==0, then device * unregistered while close proc. */ - if (netif_running(sixpack_ctrls[i]->dev)) - unregister_netdev(&(sixpack_ctrls[i]->dev)); + if (netif_running(&sixpack_ctrls[i]->dev)) + unregister_netdev(&sixpack_ctrls[i]->dev); kfree(sixpack_ctrls[i]); sixpack_ctrls[i] = NULL; diff -u --recursive --new-file v2.3.47/linux/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c --- v2.3.47/linux/drivers/net/ioc3-eth.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/ioc3-eth.c Thu Feb 24 22:49:19 2000 @@ -0,0 +1,905 @@ +/* $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. + * + * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card. + * + * Copyright (C) 1999, 2000 Ralf Baechle + * Copyright (C) 1995, 1999, 2000 by Silicon Graphics, Inc. + * + * Reporting bugs: + * + * If you find problems with this drivers, then if possible do the + * following. Hook up a terminal to the MSC port, send an NMI to the CPUs + * by typing ^Tnmi (where ^T stands for -T). You'll see something + * like: + * 1A 000: + * 1A 000: *** NMI while in Kernel and no NMI vector installed on node 0 + * 1A 000: *** Error EPC: 0xffffffff800265e4 (0xffffffff800265e4) + * 1A 000: *** Press ENTER to continue. + * + * Next enter the command ``lw i:0x86000f0 0x18'' and include this + * commands output which will look like below with your bugreport. + * + * 1A 000: POD MSC Dex> lw i:0x86000f0 0x18 + * 1A 000: 92000000086000f0: 0021f28c 00000000 00000000 00000000 + * 1A 000: 9200000008600100: a5000000 01cde000 00000000 000004e0 + * 1A 000: 9200000008600110: 00000650 00000000 00110b15 00000000 + * 1A 000: 9200000008600120: 006d0005 77bbca0a a5000000 01ce0000 + * 1A 000: 9200000008600130: 80000500 00000500 00002538 05690008 + * 1A 000: 9200000008600140: 00000000 00000000 000003e1 0000786d + * + * To do: + * + * - ioc3_close() should attempt to shutdown the adapter somewhat more + * gracefully. + * - Free rings and buffers when closing or before re-initializing rings. + * - Handle allocation failures in ioc3_alloc_skb() more gracefully. + * - Handle allocation failures in ioc3_init_rings(). + * - Maybe implement private_ioctl(). + * - Use prefetching for large packets. What is a good lower limit for + * prefetching? + * - We're probably allocating a bit too much memory. + * - Workarounds for various PHYs. + * - Proper autonegotiation. + * - What exactly is net_device_stats.tx_dropped supposed to count? + * - Use hardware checksums. + * - Convert to using the PCI infrastructure / IOC3 meta driver. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 32 RX buffers. This is tunable in the range of 16 <= x < 512. */ +#define RX_BUFFS 32 + +static void ioc3_set_multicast_list(struct net_device *dev); +static int ioc3_open(struct net_device *dev); +static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void ioc3_timeout(struct net_device *dev); +static int ioc3_close(struct net_device *dev); +static inline unsigned int ioc3_hash(const unsigned char *addr); + +static const char ioc3_str[] = "IOC3 Ethernet"; + +/* Private per NIC data of the driver. */ +struct ioc3_private { + struct ioc3 *regs; + int phy; + unsigned long rxr; /* pointer to receiver ring */ + struct ioc3_etxd *txr; + struct sk_buff *rx_skbs[512]; + struct sk_buff *tx_skbs[128]; + struct net_device_stats stats; + int rx_ci; /* RX consumer index */ + int rx_pi; /* RX producer index */ + int tx_ci; /* TX consumer index */ + int tx_pi; /* TX producer index */ +}; + +/* We use this to acquire receive skb's that we can DMA directly into. */ +#define ALIGNED_RX_SKB_ADDR(addr) \ + ((((unsigned long)(addr) + (128 - 1)) & ~(128 - 1)) - (unsigned long)(addr)) + +#define ioc3_alloc_skb(__length, __gfp_flags) \ +({ struct sk_buff *__skb; \ + __skb = alloc_skb((__length) + 128, (__gfp_flags)); \ + if (__skb) { \ + int __offset = ALIGNED_RX_SKB_ADDR(__skb->data); \ + if(__offset) \ + skb_reserve(__skb, __offset); \ + } \ + __skb; \ +}) + +/* BEWARE: The IOC3 documentation documents the size of rx buffers as + 1644 while it's actually 1664. This one was nasty to track down ... */ +#define RX_OFFSET 10 +#define RX_BUF_ALLOC_SIZE (1664 + RX_OFFSET + 128) + +/* DMA barrier to separate cached and uncached accesses. */ +#define BARRIER() \ + __asm__("sync" ::: "memory") + +/* This El Cheapo implementatin of TX_BUFFS_AVAIL may leave on entry unused. + Since the TX ring has 128 entries which is fairly large we don't care and + use this, more efficient implementation. */ +#define TX_BUFFS_AVAIL(ip) \ +({ \ + struct ioc3_private *_ip = (ip); \ + ((512 + _ip->tx_ci + 1) - _ip->tx_pi) & 511; \ +}) +//#undef TX_BUFFS_AVAIL +//#define TX_BUFFS_AVAIL(ip) (1) + + +#define IOC3_SIZE 0x100000 + +#define ioc3_r(reg) \ +({ \ + u32 __res; \ + __res = ioc3->reg; \ + __res; \ +}) + +#define ioc3_w(reg,val) \ +do { \ + (ioc3->reg = (val)); \ +} while(0) + +static inline u32 +mcr_pack(u32 pulse, u32 sample) +{ + return (pulse << 10) | (sample << 2); +} + +static int +nic_wait(struct ioc3 *ioc3) +{ + u32 mcr; + + do { + mcr = ioc3_r(mcr); + } while (!(mcr & 2)); + + return mcr & 1; +} + +static int +nic_reset(struct ioc3 *ioc3) +{ + int presence; + + ioc3_w(mcr, mcr_pack(500, 65)); + presence = nic_wait(ioc3); + + ioc3_w(mcr, mcr_pack(0, 500)); + nic_wait(ioc3); + + return presence; +} + +/* + * Read a byte from an iButton device + */ +static u32 +nic_read_byte(struct ioc3 *ioc3) +{ + u32 result = 0; + int i; + + for (i = 0; i < 8; i++) { + ioc3_w(mcr, mcr_pack(6, 13)); + result = (result >> 1) | (nic_wait(ioc3) << 7); + + ioc3_w(mcr, mcr_pack(0, 100)); + nic_wait(ioc3); + } + + return result; +} + +/* + * Write a byte to an iButton device + */ +static void +nic_write_byte(struct ioc3 *ioc3, int byte) +{ + int i, bit; + + for (i = 8; i; i--) { + bit = byte & 1; + byte >>= 1; + + if (bit) + ioc3_w(mcr, mcr_pack(6, 110)); + else + ioc3_w(mcr, mcr_pack(80, 30)); + nic_wait(ioc3); + } +} + +static void nic_show_regnr(struct ioc3 *ioc3) +{ + const char *type; + u8 regnr[8]; + int i; + + nic_write_byte(ioc3, 0x33); + for (i = 0; i < 8; i++) + regnr[i] = nic_read_byte(ioc3); + + switch(regnr[0]) { + case 0x01: type = "DS1990A"; break; + case 0x91: type = "DS1981U"; break; + default: type = "unknown"; break; + } + + printk("Found %s NIC, registration number " + "%02x:%02x:%02x:%02x:%02x:%02x, CRC %02x.\n", type, + regnr[1], regnr[2], regnr[3], regnr[4], regnr[5], regnr[6], + regnr[7]); +} + +/* + * Read the NIC (Number-In-a-Can) device. + */ +static void ioc3_get_eaddr(struct net_device *dev, struct ioc3 *ioc3) +{ + u8 nic[14]; + int i; + + ioc3_w(gpcr_s, (1 << 21)); + + nic_reset(ioc3); + nic_show_regnr(ioc3); + + nic_reset(ioc3); + nic_write_byte(ioc3, 0xcc); + nic_write_byte(ioc3, 0xf0); + nic_write_byte(ioc3, 0x00); + nic_write_byte(ioc3, 0x00); + + for (i = 13; i >= 0; i--) + nic[i] = nic_read_byte(ioc3); + + printk("Ethernet address is "); + for (i = 2; i < 8; i++) { + dev->dev_addr[i - 2] = nic[i]; + printk("%02x", nic[i]); + if (i < 7) + printk(":"); + } + printk(".\n"); +} + +static u16 mii_read(struct ioc3 *ioc3, int phy, int reg) +{ + while (ioc3->micr & MICR_BUSY); + ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg | MICR_READTRIG; + while (ioc3->micr & MICR_BUSY); + + return ioc3->midr & MIDR_DATA_MASK; +} + +static void mii_write(struct ioc3 *ioc3, int phy, int reg, u16 data) +{ + while (ioc3->micr & MICR_BUSY); + ioc3->midr = data; + ioc3->micr = (phy << MICR_PHYADDR_SHIFT) | reg; + while (ioc3->micr & MICR_BUSY); +} + +static struct net_device_stats *ioc3_get_stats(struct net_device *dev) +{ + struct ioc3_private *ip = (struct ioc3_private *) dev->priv; + struct ioc3 *ioc3 = ip->regs; + + ip->stats.collisions += (ioc3->etcdc & ETCDC_COLLCNT_MASK); + return &ip->stats; +} + +static inline void +ioc3_rx(struct net_device *dev, struct ioc3_private *ip, struct ioc3 *ioc3) +{ + struct sk_buff *skb, *new_skb; + int rx_entry, n_entry, len; + struct ioc3_erxbuf *rxb; + unsigned long *rxr; + u32 w0, err; + + rxr = (unsigned long *) ip->rxr; /* Ring base */ + rx_entry = ip->rx_ci; /* RX consume index */ + n_entry = ip->rx_pi; + + skb = ip->rx_skbs[rx_entry]; + rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); + w0 = rxb->w0; + + while (w0 & ERXBUF_V) { + ioc3->eisr = EISR_RXTIMERINT; /* Ack */ + ioc3->eisr; /* Flush */ + + err = rxb->err; /* It's valid ... */ + if (err & ERXBUF_GOODPKT) { + len = (w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff; + skb_trim(skb, len); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); + if (!new_skb) { + /* Ouch, drop packet and just recycle packet + to keep the ring filled. */ + ip->stats.rx_dropped++; + new_skb = skb; + goto next; + } + + new_skb->dev = dev; + + /* Because we reserve afterwards. */ + skb_put(new_skb, (1664 + RX_OFFSET)); + rxb = (struct ioc3_erxbuf *) new_skb->data; + skb_reserve(new_skb, RX_OFFSET); + + ip->stats.rx_packets++; /* Statistics */ + ip->stats.rx_bytes += len; + + goto next; + } + if (err & (ERXBUF_CRCERR | ERXBUF_FRAMERR | ERXBUF_CODERR | + ERXBUF_INVPREAMB | ERXBUF_BADPKT | ERXBUF_CARRIER)) { + /* We don't send the skbuf to the network layer, so + just recycle it. */ + new_skb = skb; + + if (err & ERXBUF_CRCERR) /* Statistics */ + ip->stats.rx_crc_errors++; + if (err & ERXBUF_FRAMERR) + ip->stats.rx_frame_errors++; + ip->stats.rx_errors++; + } + +next: + ip->rx_skbs[n_entry] = new_skb; + rxr[n_entry] = (0xa5UL << 56) | + ((unsigned long) rxb & TO_PHYS_MASK); + rxb->w0 = 0; /* Clear valid flag */ + n_entry = (n_entry + 1) & 511; /* Update erpir */ + ioc3->erpir = (n_entry << 3) | ERPIR_ARM; + + /* Now go on to the next ring entry. */ + rx_entry = (rx_entry + 1) & 511; + skb = ip->rx_skbs[rx_entry]; + rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET); + w0 = rxb->w0; + } + ip->rx_pi = n_entry; + ip->rx_ci = rx_entry; + + return; +} + +static inline void +ioc3_tx(struct ioc3_private *ip, struct ioc3 *ioc3) +{ + int tx_entry, o_entry; + struct sk_buff *skb; + u32 etcir; + + etcir = ioc3->etcir; + tx_entry = (etcir >> 7) & 127; + o_entry = ip->tx_ci; + + while (o_entry != tx_entry) { + ioc3->eisr = EISR_TXEXPLICIT; /* Ack */ + ioc3->eisr; /* Flush */ + + skb = ip->tx_skbs[o_entry]; + ip->stats.tx_packets++; + ip->stats.tx_bytes += skb->len; + dev_kfree_skb(skb); + ip->tx_skbs[o_entry] = NULL; + + o_entry = (o_entry + 1) & 127; /* Next */ + + etcir = ioc3->etcir; /* More pkts sent? */ + tx_entry = (etcir >> 7) & 127; + } + ip->tx_ci = o_entry; +} + +/* + * Deal with fatal IOC3 errors. For now let's panic. This condition might + * be caused by a hard or software problems, so we should try to recover + * more gracefully if this ever happens. + */ +static void +ioc3_error(struct net_device *dev, struct ioc3_private *ip, + struct ioc3 *ioc3, u32 eisr) +{ + if (eisr & (EISR_RXMEMERR | EISR_TXMEMERR)) { + if (eisr & EISR_RXMEMERR) { + panic("%s: RX PCI error.\n", dev->name); + } + if (eisr & EISR_TXMEMERR) { + panic("%s: TX PCI error.\n", dev->name); + } + } +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)_dev; + struct ioc3_private *ip = dev->priv; + struct ioc3 *ioc3 = ip->regs; + u32 eisr, eier; + + ip = dev->priv; + + eier = ioc3->eier; /* Disable eth ints */ + ioc3->eier = 0; + eisr = ioc3->eisr; + __sti(); + + if (eisr & EISR_RXTIMERINT) { + ioc3_rx(dev, ip, ioc3); + } + if (eisr & EISR_TXEXPLICIT) { + ioc3_tx(ip, ioc3); + } + if (eisr & (EISR_RXMEMERR | EISR_TXMEMERR)) { + ioc3_error(dev, ip, ioc3, eisr); + } + + if ((TX_BUFFS_AVAIL(ip) >= 0) && netif_queue_stopped(dev)) { + netif_wake_queue(dev); + } + + __cli(); + ioc3->eier = eier; + + return; +} + +int +ioc3_eth_init(struct net_device *dev, struct ioc3_private *p, struct ioc3 *ioc3) +{ + u16 word, mii0, mii_status, mii2, mii3, mii4; + u32 vendor, model, rev; + int i, phy; + + ioc3->emcr = EMCR_RST; /* Reset */ + ioc3->emcr; /* flush WB */ + udelay(4); /* Give it time ... */ + ioc3->emcr = 0; + + phy = -1; + for (i = 0; i < 32; i++) { + word = mii_read(ioc3, i, 2); + if ((word != 0xffff) & (word != 0x0000)) { + phy = i; + break; /* Found a PHY */ + } + } + if (phy == -1) { + printk("Didn't find a PHY, goodbye.\n"); + return -ENODEV; + } + p->phy = phy; + + mii0 = mii_read(ioc3, phy, 0); + mii_status = mii_read(ioc3, phy, 1); + mii2 = mii_read(ioc3, phy, 2); + mii3 = mii_read(ioc3, phy, 3); + mii4 = mii_read(ioc3, phy, 4); + vendor = (mii2 << 12) | (mii3 >> 4); + model = (mii3 >> 4) & 0x3f; + rev = mii3 & 0xf; + printk("Ok, using PHY %d, vendor 0x%x, model %d, rev %d.\n", + phy, vendor, model, rev); + printk(KERN_INFO "%s: MII transceiver found at MDIO address " + "%d, config %4.4x status %4.4x.\n", + dev->name, phy, mii0, mii_status); + + /* Autonegotiate 100mbit and fullduplex. */ + mii_write(ioc3, phy, 0, mii0 | 0x3100); + mdelay(1000); + mii_status = mii_read(ioc3, phy, 1); + + return 0; /* XXX */ +} + +/* To do: For reinit of the ring we have to cleanup old skbs first ... */ +static void +ioc3_init_rings(struct net_device *dev, struct ioc3_private *p, + struct ioc3 *ioc3) +{ + struct ioc3_erxbuf *rxb; + unsigned long *rxr; + unsigned long ring; + int i; + + /* Allocate and initialize rx ring. 4kb = 512 entries */ + p->rxr = get_free_page(GFP_KERNEL); + rxr = (unsigned long *) p->rxr; + + /* Now the rx buffers. The RX ring may be larger but we only + allocate 16 buffers for now. Need to tune this for performance + and memory later. */ + for (i = 0; i < RX_BUFFS; i++) { + struct sk_buff *skb; + + skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, 0); + if (!skb) { + show_free_areas(); + continue; + } + + p->rx_skbs[i] = skb; + skb->dev = dev; + + /* Because we reserve afterwards. */ + skb_put(skb, (1664 + RX_OFFSET)); + rxb = (struct ioc3_erxbuf *) skb->data; + rxb->w0 = 0; /* Clear valid bit */ + rxr[i] = (0xa5UL << 56) | ((unsigned long) rxb & TO_PHYS_MASK); + skb_reserve(skb, RX_OFFSET); + } + + /* Now the rx ring base, consume & produce registers. */ + ring = (0xa5UL << 56) | (p->rxr & TO_PHYS_MASK); + ioc3->erbr_h = ring >> 32; + ioc3->erbr_l = ring & 0xffffffff; + p->rx_ci = 0; + ioc3->ercir = (p->rx_ci << 3); + p->rx_pi = RX_BUFFS; + ioc3->erpir = (p->rx_pi << 3) | ERPIR_ARM; + + /* Allocate and initialize tx rings. 16kb = 128 bufs. */ + p->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2); + ring = (0xa5UL << 56) | ((unsigned long)p->txr & TO_PHYS_MASK); + + /* Now the tx ring base, consume & produce registers. */ + ioc3->etbr_h = ring >> 32; + ioc3->etbr_l = ring & 0xffffffff; + p->tx_pi = 0; + ioc3->etpir = (p->tx_pi << 7); + p->tx_ci = 0; + ioc3->etcir = (p->tx_pi << 7); + ioc3->etcir; /* Flush */ +} + +void +ioc3_ssram_disc(struct ioc3_private *ip) +{ + struct ioc3 *ioc3 = ip->regs; + volatile u32 *ssram0 = &ioc3->ssram[0x0000]; + volatile u32 *ssram1 = &ioc3->ssram[0x4000]; + unsigned int pattern = 0x5555; + + /* Assume the larger size SSRAM and enable parity checking */ + ioc3->emcr |= (EMCR_BUFSIZ | EMCR_RAMPAR); + + *ssram0 = pattern; + *ssram1 = ~pattern & IOC3_SSRAM_DM; + + if ((*ssram0 & IOC3_SSRAM_DM) != pattern || + (*ssram1 & IOC3_SSRAM_DM) != (~pattern & IOC3_SSRAM_DM)) { + /* set ssram size to 64 KB */ + ioc3->emcr &= ~EMCR_BUFSIZ; + printk("IOC3 SSRAM has 64 kbyte.\n"); + } else { + //ei->ei_ssram_bits = EMCR_BUFSIZ | EMCR_RAMPAR; + printk("IOC3 SSRAM has 64 kbyte.\n"); + } +} + +static void ioc3_probe1(struct net_device *dev, struct ioc3 *ioc3) +{ + struct ioc3_private *p; + + dev = init_etherdev(dev, 0); + p = (struct ioc3_private *) kmalloc(sizeof(*p), GFP_KERNEL); + memset(p, 0, sizeof(*p)); + dev->priv = p; + dev->irq = IOC3_ETH_INT; + + p->regs = ioc3; + + ioc3_eth_init(dev, p, ioc3); + ioc3_ssram_disc(p); + ioc3_get_eaddr(dev, ioc3); + ioc3_init_rings(dev, p, ioc3); + + /* Misc registers */ + ioc3->erbar = 0; + ioc3->etcsr = (17<etcdc; /* Clear on read */ + ioc3->ercsr = 15; /* RX low watermark */ + ioc3->ertr = 0; /* Interrupt immediately */ + ioc3->emar_h = (dev->dev_addr[5] << 8) | dev->dev_addr[4]; + ioc3->emar_l = (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | + (dev->dev_addr[1] << 8) | dev->dev_addr[0]; + ioc3->ehar_h = ioc3->ehar_l = 0; + ioc3->ersr = 42; /* XXX should be random */ + //ioc3->erpir = ERPIR_ARM; + + /* The IOC3-specific entries in the device structure. */ + dev->open = &ioc3_open; + dev->hard_start_xmit = &ioc3_start_xmit; + dev->tx_timeout = ioc3_timeout; + dev->watchdog_timeo = (400 * HZ) / 1000; + dev->stop = &ioc3_close; + dev->get_stats = &ioc3_get_stats; + dev->set_multicast_list = &ioc3_set_multicast_list; +} + +int +ioc3_probe(struct net_device *dev) +{ + static int initialized; + struct ioc3 *ioc3; + nasid_t nid; + + if (initialized) /* Only initialize once ... */ + return 0; + initialized++; + + nid = get_nasid(); + ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base; + ioc3_probe1(dev, ioc3); + + return 0; +} + +static int +ioc3_open(struct net_device *dev) +{ + struct ioc3_private *ip = dev->priv; + struct ioc3 *ioc3 = ip->regs; + unsigned long flags; + + save_flags(flags); cli(); + if (request_irq(dev->irq, ioc3_interrupt, 0, ioc3_str, dev)) { + printk("%s: Can't get irq %d\n", dev->name, dev->irq); + restore_flags(flags); + + return -EAGAIN; + } + + //ioc3_eth_init(dev, p, ioc3); + + ioc3->emcr = ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN | + EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN; + ioc3->eier = EISR_RXTIMERINT | EISR_TXEXPLICIT | /* Interrupts ... */ + EISR_RXMEMERR | EISR_TXMEMERR; + + netif_wake_queue(dev); + restore_flags(flags); + + MOD_INC_USE_COUNT; + + return 0; +} + +static int +ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + unsigned long data; + struct ioc3_private *ip = dev->priv; + struct ioc3 *ioc3 = ip->regs; + unsigned int len; + struct ioc3_etxd *desc; + int produce; + + if (!TX_BUFFS_AVAIL(ip)) { + return 1; + } + + data = (unsigned long) skb->data; + len = skb->len; + + produce = ip->tx_pi; + desc = &ip->txr[produce]; + + if (len <= 104) { + /* Short packet, let's copy it directly into the ring. */ + memcpy(desc->data, skb->data, skb->len); + if (len < ETH_ZLEN) { + /* Very short packet, pad with zeros at the end. */ + memset(desc->data + len, 0, ETH_ZLEN - len); + len = ETH_ZLEN; + } + desc->cmd = len | ETXD_INTWHENDONE | ETXD_D0V; + desc->bufcnt = len; + } if ((data ^ (data + len)) & 0x4000) { + unsigned long b2, s1, s2; + + b2 = (data | 0x3fffUL) + 1UL; + 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); + } 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); + } + + BARRIER(); + + dev->trans_start = jiffies; + ip->tx_skbs[produce] = skb; /* Remember skb */ + produce = (produce + 1) & 127; + ip->tx_pi = produce; + ioc3->etpir = produce << 7; /* Fire ... */ + + if (TX_BUFFS_AVAIL(ip)) + netif_wake_queue(dev); + + return 0; +} + +static void ioc3_timeout(struct net_device *dev) +{ + printk("%s: transmit timed out, resetting\n", dev->name); + /* XXX should reset device here. */ + + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + +static int +ioc3_close(struct net_device *dev) +{ + struct ioc3_private *ip = dev->priv; + struct ioc3 *ioc3 = ip->regs; + + netif_stop_queue(dev); + + ioc3->emcr = 0; /* Shutup */ + ioc3->eier = 0; /* Disable interrupts */ + ioc3->eier; /* Flush */ + free_irq(dev->irq, dev); + + MOD_DEC_USE_COUNT; + + return 0; +} + +#if 0 +/* Initialize the NIC */ +static int +ioc3_init(struct ioc3_private *p, struct pci_dev *dev) +{ +#if 0 + unsigned long base; + struct ioc3 *ioc3; + + pci_set_master(dev); + base = dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK; + printk("Base address at %08lx\n", base); + + p->regs = ioc3 = ioremap (base, IOC3_SIZE); + printk("Remapped base address to %08lx\n", (unsigned long) regs); + + read_nic(ioc3); + + return 0; +#endif + panic(__FUNCTION__" has been called.\n"); +} +#endif + +/* + * 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; + + 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 &= 0x3f; /* bit reverse lowest 6 bits for hash index */ + for (bits = 6; --bits >= 0; ) { + temp <<= 1; + temp |= (crc & 0x1); + crc >>= 1; + } + + return temp; +} + +static void ioc3_set_multicast_list(struct net_device *dev) +{ + struct dev_mc_list *dmi = dev->mc_list; + char *addr = dmi->dmi_addr; + struct ioc3_private *p; + struct ioc3 *ioc3; + u64 ehar = 0; + int i; + + p = dev->priv; + ioc3 = p->regs; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); + ioc3->emcr |= EMCR_PROMISC; + ioc3->emcr; + } else { + ioc3->emcr &= ~EMCR_PROMISC; /* Clear promiscuous. */ + ioc3->emcr; + + if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) { + /* Too many for hashing to make sense or we want all + multicast packets anyway, so skip computing all the + hashes and just accept all packets. */ + ioc3->ehar_h = 0xffffffff; + ioc3->ehar_l = 0xffffffff; + } else { + for (i = 0; i < dev->mc_count; i++) { + dmi = dmi->next; + + if (!(*addr & 1)) + continue; + + ehar |= (1 << ioc3_hash(addr)); + } + ioc3->ehar_h = ehar >> 32; + ioc3->ehar_l = ehar & 0xffffffff; + } + } +} + +#ifdef MODULE +MODULE_AUTHOR("Ralf Baechle "); +MODULE_DESCRIPTION("SGI IOC3 Ethernet driver"); + +int +init_module(void) +{ + struct pci_dev *dev = NULL; + + while ((dev = pci_find_device(PCI_VENDOR_ID_SGI, 0x0003, dev))) { + ioc3_init(&p, dev); + } + + return -EBUSY; +} + +void +cleanup_module(void) +{ + printk("cleanup_module called\n"); +} +#endif /* MODULE */ diff -u --recursive --new-file v2.3.47/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c --- v2.3.47/linux/drivers/net/irda/nsc-ircc.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/irda/nsc-ircc.c Tue Feb 22 22:28:59 2000 @@ -6,7 +6,7 @@ * Status: Stable. * Author: Dag Brattli * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Fri Jan 28 12:10:10 2000 + * Modified at: Fri Feb 18 01:48:51 2000 * Modified by: Dag Brattli * * Copyright (c) 1998-2000 Dag Brattli @@ -42,6 +42,7 @@ ********************************************************************/ #include + #include #include #include @@ -1431,8 +1432,10 @@ /* We must empty the status FIFO no matter what */ len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8); - if (st_fifo->tail >= MAX_RX_WINDOW) + if (st_fifo->tail >= MAX_RX_WINDOW) { + IRDA_DEBUG(0, __FUNCTION__ "(), window is full!\n"); continue; + } st_fifo->entries[st_fifo->tail].status = status; st_fifo->entries[st_fifo->tail].len = len; @@ -1492,7 +1495,18 @@ st_fifo->pending_bytes += len; st_fifo->entries[st_fifo->head].status = status; st_fifo->entries[st_fifo->head].len = len; - + /* + * DMA not finished yet, so try again + * later, set timer value, resolution + * 125 us + */ + switch_bank(iobase, BANK4); + outb(0x02, iobase+TMRL); /* x 125 us */ + outb(0x00, iobase+TMRH); + + /* Start timer */ + outb(IRCR1_TMR_EN, iobase+IRCR1); + /* Restore bank register */ outb(bank, iobase+BSR); @@ -1597,7 +1611,7 @@ else { self->stats.tx_packets++; - netif_wakeup_queue(self->netdev); + netif_wake_queue(self->netdev); self->ier = IER_TXEMP_IE; } @@ -1648,21 +1662,12 @@ /* Status FIFO event*/ if (eir & EIR_SFIF_EV) { + /* Check if DMA has finished */ if (nsc_ircc_dma_receive_complete(self, iobase)) { /* Wait for next status FIFO interrupt */ self->ier = IER_SFIF_IE; } else { - /* - * DMA not finished yet, so try again later, set - * timer value, resolution 125 us - */ - switch_bank(iobase, BANK4); - outb(0x02, iobase+TMRL); /* 2 * 125 us */ - outb(0x00, iobase+TMRH); - - /* Start timer */ - outb(IRCR1_TMR_EN, iobase+IRCR1); - self->ier = IER_TMR_IE | IER_SFIF_IE; + self->ier = IER_SFIF_IE | IER_TMR_IE; } } else if (eir & EIR_TMR_EV) { /* Timer finished */ /* Disable timer */ @@ -1677,15 +1682,17 @@ if (self->io.direction == IO_XMIT) { nsc_ircc_dma_xmit(self, iobase); - /* Interrupt on DMA */ + /* Interrupt on DMA */ self->ier = IER_DMA_IE; } else { - /* Check if DMA has now finished */ - nsc_ircc_dma_receive_complete(self, iobase); - - self->ier = IER_SFIF_IE; + /* Check (again) if DMA has finished */ + if (nsc_ircc_dma_receive_complete(self, iobase)) { + self->ier = IER_SFIF_IE; + } else { + self->ier = IER_SFIF_IE | IER_TMR_IE; + } } - } else if (eir & EIR_DMA_EV) { + } else if (eir & EIR_DMA_EV) { /* Finished with all transmissions? */ if (nsc_ircc_dma_xmit_complete(self)) { /* Check if there are more frames to be transmitted */ diff -u --recursive --new-file v2.3.47/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c --- v2.3.47/linux/drivers/net/irda/smc-ircc.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/irda/smc-ircc.c Tue Feb 22 22:28:59 2000 @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Thomas Davis (tadavis@jps.net) * Created at: - * Modified at: Fri Jan 21 09:41:08 2000 + * Modified at: Tue Feb 22 10:05:06 2000 * Modified by: Dag Brattli * * Copyright (c) 1999-2000 Dag Brattli @@ -567,7 +567,6 @@ "(), using irport to change speed to %d\n", speed); irport_change_speed(self->irport, speed); } - dev->tbusy = 0; register_bank(iobase, 1); outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), @@ -617,9 +616,7 @@ if ((speed = irda_get_speed(skb)) != self->io.speed) self->new_speed = speed; - /* Lock transmit buffer */ - if (irda_lock((void *) &dev->tbusy) == FALSE) - return -EBUSY; + netif_stop_queue(dev); memcpy(self->tx_buff.head, skb->data, skb->len); @@ -741,11 +738,7 @@ self->new_speed = 0; } - /* Unlock tx_buff and request another frame */ - self->netdev->tbusy = 0; /* Unlock */ - - /* Tell the network layer, that we can accept more frames */ - mark_bh(NET_BH); + netif_wake_queue(self->netdev); } /* @@ -875,7 +868,6 @@ iobase = self->io.fir_base; spin_lock(&self->lock); - dev->interrupt = 1; register_bank(iobase, 0); iir = inb(iobase+IRCC_IIR); @@ -898,7 +890,6 @@ register_bank(iobase, 0); outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER); - dev->interrupt = 0; spin_unlock(&self->lock); } diff -u --recursive --new-file v2.3.47/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c --- v2.3.47/linux/drivers/net/pcmcia/3c589_cs.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/pcmcia/3c589_cs.c Sun Feb 20 21:59:27 2000 @@ -788,8 +788,7 @@ while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { - if (!netif_device_present(dev)) || - ((status & 0xe000) != 0x2000)) { + if (!netif_device_present(dev) || ((status & 0xe000) != 0x2000)) { DEBUG(1, "%s: interrupt from dead card\n", dev->name); break; } diff -u --recursive --new-file v2.3.47/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c --- v2.3.47/linux/drivers/net/sgiseeq.c Wed Aug 18 11:36:42 1999 +++ linux/drivers/net/sgiseeq.c Thu Feb 24 22:49:19 2000 @@ -31,7 +31,8 @@ #include #include -#include +#include +#include #include #include "sgiseeq.h" @@ -70,12 +71,12 @@ struct sgiseeq_rx_desc { struct hpc_dma_desc rdma; - unsigned long buf_vaddr; + signed int buf_vaddr; }; struct sgiseeq_tx_desc { struct hpc_dma_desc tdma; - unsigned long buf_vaddr; + signed int buf_vaddr; }; /* Warning: This structure is layed out in a certain way because @@ -86,7 +87,7 @@ /* Ptrs to the descriptors in KSEG1 uncached space. */ struct sgiseeq_rx_desc *rx_desc; struct sgiseeq_tx_desc *tx_desc; - unsigned long _padding[30]; /* Pad out to largest cache line size. */ + unsigned int _padding[30]; /* Pad out to largest cache line size. */ struct sgiseeq_rx_desc rxvector[SEEQ_RX_BUFFERS]; struct sgiseeq_tx_desc txvector[SEEQ_TX_BUFFERS]; @@ -140,7 +141,7 @@ int i; sregs->tstat = SEEQ_TCMD_RB0; - for(i = 0; i < 6; i++) + for (i = 0; i < 6; i++) sregs->rw.eth_addr[i] = dev->dev_addr[i]; } @@ -154,7 +155,7 @@ volatile struct sgiseeq_init_block *ib = &sp->srings; int i; - dev->tbusy = 1; + netif_stop_queue(dev); sp->rx_new = sp->tx_new = 0; sp->rx_old = sp->tx_old = 0; @@ -180,8 +181,8 @@ } /* And now the rx ring. */ - for(i = 0; i < SEEQ_RX_BUFFERS; i++) { - if(!ib->rx_desc[i].rdma.pbuf) { + for (i = 0; i < SEEQ_RX_BUFFERS; i++) { + if (!ib->rx_desc[i].rdma.pbuf) { unsigned long buffer; buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL); @@ -210,29 +211,29 @@ return; once++; printk("RING DUMP:\n"); - for(i = 0; i < SEEQ_RX_BUFFERS; i++) { - printk("RX [%d]: @(%p) [%08lx,%08lx,%08lx] ", + for (i = 0; i < SEEQ_RX_BUFFERS; i++) { + printk("RX [%d]: @(%p) [%08x,%08x,%08x] ", i, (&r[i]), r[i].rdma.pbuf, r[i].rdma.cntinfo, r[i].rdma.pnext); i += 1; - printk("-- [%d]: @(%p) [%08lx,%08lx,%08lx]\n", + printk("-- [%d]: @(%p) [%08x,%08x,%08x]\n", i, (&r[i]), r[i].rdma.pbuf, r[i].rdma.cntinfo, r[i].rdma.pnext); } - for(i = 0; i < SEEQ_TX_BUFFERS; i++) { - printk("TX [%d]: @(%p) [%08lx,%08lx,%08lx] ", + for (i = 0; i < SEEQ_TX_BUFFERS; i++) { + printk("TX [%d]: @(%p) [%08x,%08x,%08x] ", i, (&t[i]), t[i].tdma.pbuf, t[i].tdma.cntinfo, t[i].tdma.pnext); i += 1; - printk("-- [%d]: @(%p) [%08lx,%08lx,%08lx]\n", + printk("-- [%d]: @(%p) [%08x,%08x,%08x]\n", i, (&t[i]), t[i].tdma.pbuf, t[i].tdma.cntinfo, t[i].tdma.pnext); } printk("INFO: [rx_new = %d rx_old=%d] [tx_new = %d tx_old = %d]\n", gpriv->rx_new, gpriv->rx_old, gpriv->tx_new, gpriv->tx_old); - printk("RREGS: rx_cbptr[%08lx] rx_ndptr[%08lx] rx_ctrl[%08lx]\n", + printk("RREGS: rx_cbptr[%08x] rx_ndptr[%08x] rx_ctrl[%08x]\n", hregs->rx_cbptr, hregs->rx_ndptr, hregs->rx_ctrl); - printk("TREGS: tx_cbptr[%08lx] tx_ndptr[%08lx] tx_ctrl[%08lx]\n", + printk("TREGS: tx_cbptr[%08x] tx_ndptr[%08x] tx_ctrl[%08x]\n", hregs->tx_cbptr, hregs->tx_ndptr, hregs->tx_ctrl); } #endif @@ -250,7 +251,7 @@ seeq_init_ring(dev); /* Setup to field the proper interrupt types. */ - if(sp->is_edlc) { + if (sp->is_edlc) { sregs->tstat = (TSTAT_INIT_EDLC); sregs->rw.wregs.control = sp->control; sregs->rw.wregs.frame_gap = 0; @@ -269,14 +270,14 @@ static inline void record_rx_errors(struct sgiseeq_private *sp, unsigned char status) { - if(status & SEEQ_RSTAT_OVERF || - status & SEEQ_RSTAT_SFRAME) + if (status & SEEQ_RSTAT_OVERF || + status & SEEQ_RSTAT_SFRAME) sp->stats.rx_over_errors++; - if(status & SEEQ_RSTAT_CERROR) + if (status & SEEQ_RSTAT_CERROR) sp->stats.rx_crc_errors++; - if(status & SEEQ_RSTAT_DERROR) + if (status & SEEQ_RSTAT_DERROR) sp->stats.rx_frame_errors++; - if(status & SEEQ_RSTAT_REOF) + if (status & SEEQ_RSTAT_REOF) sp->stats.rx_errors++; } @@ -284,7 +285,7 @@ volatile struct hpc3_ethregs *hregs, volatile struct sgiseeq_regs *sregs) { - if(!(hregs->rx_ctrl & HPC3_ERXCTRL_ACTIVE)) { + if (!(hregs->rx_ctrl & HPC3_ERXCTRL_ACTIVE)) { hregs->rx_ndptr = PHYSADDR(&sp->srings.rx_desc[sp->rx_new]); seeq_go(sp, hregs, sregs); } @@ -308,14 +309,14 @@ /* Service every received packet. */ for_each_rx(rd, sp) { len = (PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3); - pkt_pointer = (unsigned char *)rd->buf_vaddr; + pkt_pointer = (unsigned char *)(long)rd->buf_vaddr; pkt_status = pkt_pointer[len + 2]; - if(pkt_status & SEEQ_RSTAT_FIG) { + if (pkt_status & SEEQ_RSTAT_FIG) { /* Packet is OK. */ skb = dev_alloc_skb(len + 2); - if(skb) { + if (skb) { skb->dev = dev; skb_reserve(skb, 2); skb_put(skb, len); @@ -346,7 +347,7 @@ static inline void tx_maybe_reset_collisions(struct sgiseeq_private *sp, volatile struct sgiseeq_regs *sregs) { - if(sp->is_edlc) { + if (sp->is_edlc) { sregs->rw.wregs.control = sp->control & ~(SEEQ_CTRL_XCNT); sregs->rw.wregs.control = sp->control; } @@ -361,11 +362,10 @@ * adapter. The following code is only safe iff the HPCDMA * is not active! */ - while((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) == + while ((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) == (HPCDMA_XIU | HPCDMA_ETXD)) - td = (struct sgiseeq_tx_desc *) - KSEG1ADDR(td->tdma.pnext); - if(td->tdma.cntinfo & HPCDMA_XIU) { + td = (struct sgiseeq_tx_desc *)(long) KSEG1ADDR(td->tdma.pnext); + if (td->tdma.cntinfo & HPCDMA_XIU) { hregs->tx_ndptr = PHYSADDR(td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; } @@ -381,23 +381,23 @@ tx_maybe_reset_collisions(sp, sregs); - if(!(status & (HPC3_ETXCTRL_ACTIVE | SEEQ_TSTAT_PTRANS))) { + if (!(status & (HPC3_ETXCTRL_ACTIVE | SEEQ_TSTAT_PTRANS))) { /* Oops, HPC detected some sort of error. */ - if(status & SEEQ_TSTAT_R16) + if (status & SEEQ_TSTAT_R16) sp->stats.tx_aborted_errors++; - if(status & SEEQ_TSTAT_UFLOW) + if (status & SEEQ_TSTAT_UFLOW) sp->stats.tx_fifo_errors++; - if(status & SEEQ_TSTAT_LCLS) + if (status & SEEQ_TSTAT_LCLS) sp->stats.collisions++; } /* Ack 'em... */ - for(j = sp->tx_old; j != sp->tx_new; j = NEXT_TX(j)) { + for (j = sp->tx_old; j != sp->tx_new; j = NEXT_TX(j)) { td = &sp->srings.tx_desc[j]; - if(!(td->tdma.cntinfo & (HPCDMA_XIU))) + if (!(td->tdma.cntinfo & (HPCDMA_XIU))) break; - if(!(td->tdma.cntinfo & (HPCDMA_ETXD))) { + if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) { if(!(status & HPC3_ETXCTRL_ACTIVE)) { hregs->tx_ndptr = PHYSADDR(td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; @@ -411,15 +411,6 @@ } } -static inline void tx_maybe_unbusy(struct sgiseeq_private *sp, - struct net_device *dev) -{ - if((TX_BUFFS_AVAIL(sp) >= 0) && dev->tbusy) { - dev->tbusy = 0; - mark_bh(NET_BH); - } -} - static void sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; @@ -429,17 +420,17 @@ /* Ack the IRQ and set software state. */ hregs->rx_reset = HPC3_ERXRST_CLRIRQ; - dev->interrupt = 1; /* Always check for received packets. */ sgiseeq_rx(dev, sp, hregs, sregs); /* Only check for tx acks iff we have something queued. */ - if(sp->tx_old != sp->tx_new) + if (sp->tx_old != sp->tx_new) sgiseeq_tx(dev, sp, hregs, sregs); - tx_maybe_unbusy(sp, dev); - dev->interrupt = 0; + if ((TX_BUFFS_AVAIL(sp) > 0) && netif_queue_stopped(dev)) { + netif_wake_queue(dev); + } } static int sgiseeq_open(struct net_device *dev) @@ -449,7 +440,7 @@ unsigned long flags; save_flags(flags); cli(); - if(request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, (void *) dev)) { + if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, (void *) dev)) { printk("Seeq8003: Can't get irq %d\n", dev->irq); restore_flags(flags); return -EAGAIN; @@ -457,9 +448,7 @@ init_seeq(dev, sp, sregs); - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); restore_flags(flags); return 0; } @@ -469,8 +458,7 @@ struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; volatile struct sgiseeq_regs *sregs = sp->sregs; - dev->start = 0; - dev->tbusy = 1; + netif_stop_queue(dev); /* Shutdown the Seeq. */ reset_hpc3_and_seeq(sp->hregs, sregs); @@ -488,9 +476,7 @@ init_seeq(dev, sp, sregs); dev->trans_start = jiffies; - dev->interrupt = 0; - dev->start = 1; - dev->tbusy = 0; + netif_wake_queue(dev); return 0; } @@ -501,34 +487,6 @@ sgiseeq_reset(gdev); } -static inline int verify_tx(struct sgiseeq_private *sp, - struct net_device *dev, - struct sk_buff *skb) -{ - /* Are we bolixed? */ - if(dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 20) - return 1; - - printk("%s: transmit timed out, ticks=%d resetting\n", - dev->name, tickssofar); - sgiseeq_reset(dev); - return 0; - } - /* Are we getting in someone else's way? */ - if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); - return -1; - } - - /* Can we even send anything? */ - if(!TX_BUFFS_AVAIL(sp)) - return -1; - - return 0; -} - static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; @@ -537,10 +495,7 @@ struct sgiseeq_tx_desc *td; int skblen, len, entry; - if(verify_tx(sp, dev, skb)) - return -1; /* Yeee... */ - - save_flags(flags); cli(); + save_and_cli(flags); /* Setup... */ skblen = skb->len; @@ -561,10 +516,10 @@ * entry and the HPC got to the end of the chain before we * added this new entry and restarted it. */ - memcpy((char *)td->buf_vaddr, skb->data, skblen); - td->tdma.cntinfo = ((len) & HPCDMA_BCNT) | - (HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX); - if(sp->tx_old != sp->tx_new) { + memcpy((char *)(long)td->buf_vaddr, skb->data, skblen); + td->tdma.cntinfo = (len & HPCDMA_BCNT) | + (HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX); + if (sp->tx_old != sp->tx_new) { struct sgiseeq_tx_desc *backend; backend = &sp->srings.tx_desc[PREV_TX(sp->tx_new)]; @@ -573,18 +528,28 @@ sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */ /* Maybe kick the HPC back into motion. */ - if(!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE)) + if (!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE)) kick_tx(&sp->srings.tx_desc[sp->tx_old], hregs); dev->trans_start = jiffies; dev_kfree_skb(skb); - if(TX_BUFFS_AVAIL(sp)) - dev->tbusy = 0; + if (!TX_BUFFS_AVAIL(sp)) + netif_stop_queue(dev); restore_flags(flags); + return 0; } +static void timeout(struct net_device *dev) +{ + printk("%s: transmit timed out, resetting\n", dev->name); + sgiseeq_reset(dev); + + dev->trans_start = jiffies; + netif_wake_queue(dev); +} + static struct enet_statistics *sgiseeq_get_stats(struct net_device *dev) { struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; @@ -600,7 +565,7 @@ { int i = 0; - while(i < (nbufs - 1)) { + while (i < (nbufs - 1)) { buf[i].tdma.pnext = PHYSADDR(&buf[i + 1]); buf[i].tdma.pbuf = 0; i++; @@ -612,7 +577,7 @@ { int i = 0; - while(i < (nbufs - 1)) { + while (i < (nbufs - 1)) { buf[i].rdma.pnext = PHYSADDR(&buf[i + 1]); buf[i].rdma.pbuf = 0; i++; @@ -632,20 +597,20 @@ int i; struct sgiseeq_private *sp; - if(dev == NULL) { + if (dev == NULL) { dev = init_etherdev(0, sizeof(struct sgiseeq_private)); } else { dev->priv = (struct sgiseeq_private *) get_free_page(GFP_KERNEL); - if(dev->priv == NULL) + if (dev->priv == NULL) return -ENOMEM; } - if(!version_printed++) + if (!version_printed++) printk(version); printk("%s: SGI Seeq8003 ", dev->name); - for(i = 0; i < 6; i++) + for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i] = onboard_eth_addr[i], i == 5 ? ' ': ':'); @@ -679,7 +644,7 @@ hpc3_eth_reset((volatile struct hpc3_ethregs *) hregs); sp->is_edlc = !(sregs->rw.rregs.collision_tx[0] & 0xff); - if(sp->is_edlc) { + if (sp->is_edlc) { sp->control = (SEEQ_CTRL_XCNT | SEEQ_CTRL_ACCNT | SEEQ_CTRL_SFLAG | SEEQ_CTRL_ESHORT | SEEQ_CTRL_ENCARR); @@ -688,6 +653,8 @@ dev->open = sgiseeq_open; dev->stop = sgiseeq_close; dev->hard_start_xmit = sgiseeq_start_xmit; + dev->tx_timeout = timeout; + dev->watchdog_timeo = (200 * HZ) / 1000; dev->get_stats = sgiseeq_get_stats; dev->set_multicast_list = sgiseeq_set_multicast; dev->irq = irq; @@ -699,9 +666,9 @@ static inline unsigned char str2hexnum(unsigned char c) { - if(c >= '0' && c <= '9') + if (c >= '0' && c <= '9') return c - '0'; - if(c >= 'a' && c <= 'f') + if (c >= 'a' && c <= 'f') return c - 'a' + 10; return 0; /* foo */ } @@ -710,7 +677,7 @@ { int i; - for(i = 0; i < 6; i++) { + for (i = 0; i < 6; i++) { unsigned char num; if(*str == ':') @@ -732,11 +699,12 @@ /* First get the ethernet address of the onboard * interface from ARCS. - * (This is fragile; PROM doesn't like running from cache.) + * This is fragile; PROM doesn't like running from cache. + * On MIPS64 it crashes for some other, yet unknown reason. */ ep = romvec->get_evar("eaddr"); str2eaddr(onboard_eth_addr, ep); return sgiseeq_init(dev, (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)), - &hpc3c0->ethregs, 3); + &hpc3c0->ethregs, SGI_ENET_IRQ); } diff -u --recursive --new-file v2.3.47/linux/drivers/net/sgiseeq.h linux/drivers/net/sgiseeq.h --- v2.3.47/linux/drivers/net/sgiseeq.h Mon Oct 11 15:38:15 1999 +++ linux/drivers/net/sgiseeq.h Thu Feb 24 22:49:19 2000 @@ -1,4 +1,4 @@ -/* $Id: sgiseeq.h,v 1.3 1998/08/25 09:17:45 ralf Exp $ +/* $Id: sgiseeq.h,v 1.5 1999/12/04 03:59:03 ralf Exp $ * sgiseeq.h: Defines for the Seeq8003 ethernet controller. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) @@ -7,27 +7,27 @@ #define _SGISEEQ_H struct sgiseeq_wregs { - volatile unsigned long multicase_high[2]; - volatile unsigned long frame_gap; - volatile unsigned long control; + volatile unsigned int multicase_high[2]; + volatile unsigned int frame_gap; + volatile unsigned int control; }; struct sgiseeq_rregs { - volatile unsigned long collision_tx[2]; - volatile unsigned long collision_all[2]; - volatile unsigned long _unused0; - volatile unsigned long rflags; + volatile unsigned int collision_tx[2]; + volatile unsigned int collision_all[2]; + volatile unsigned int _unused0; + volatile unsigned int rflags; }; struct sgiseeq_regs { union { - volatile unsigned long eth_addr[6]; - volatile unsigned long multicast_low[6]; + volatile unsigned int eth_addr[6]; + volatile unsigned int multicast_low[6]; struct sgiseeq_wregs wregs; struct sgiseeq_rregs rregs; } rw; - volatile unsigned long rstat; - volatile unsigned long tstat; + volatile unsigned int rstat; + volatile unsigned int tstat; }; /* Seeq8003 receive status register */ diff -u --recursive --new-file v2.3.47/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v2.3.47/linux/drivers/net/sk_g16.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/sk_g16.c Mon Feb 21 11:24:39 2000 @@ -1172,7 +1172,7 @@ * YY/MM/DD uid Description -*/ -static int SK_timeout(struct net_device *dev) +static void SK_timeout(struct net_device *dev) { printk(KERN_WARNING "%s: xmitter timed out, try to restart!\n", dev->name); SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */ diff -u --recursive --new-file v2.3.47/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c --- v2.3.47/linux/drivers/net/tokenring/olympic.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/tokenring/olympic.c Wed Feb 23 11:27:14 2000 @@ -26,10 +26,9 @@ * resource. Driver also reports the card name returned by * the pci resource. * 1/11/00 - Added spinlocks for smp - * - * To Do: + * 2/23/00 - Updated to dev_kfree_irq * - * IPv6 Multicast + * To Do: * * If Problems do Occur * Most problems can be rectified by either closing and opening the interface @@ -88,7 +87,7 @@ */ static char *version = -"Olympic.c v0.3.1 1/11/00 - Peter De Schrijver & Mike Phillips" ; +"Olympic.c v0.3.2 2/23/00 - Peter De Schrijver & Mike Phillips" ; static char *open_maj_error[] = {"No error", "Lobe Media Test", "Physical Insertion", "Address Verification", "Neighbor Notification (Ring Poll)", @@ -777,7 +776,7 @@ olympic_priv->free_tx_ring_entries++; olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len; olympic_priv->olympic_stats.tx_packets++ ; - dev_kfree_skb(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); + dev_kfree_skb_irq(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef; olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0; netif_wake_queue(dev); diff -u --recursive --new-file v2.3.47/linux/drivers/net/tulip/21142.c linux/drivers/net/tulip/21142.c --- v2.3.47/linux/drivers/net/tulip/21142.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tulip/21142.c Fri Feb 25 15:16:37 2000 @@ -0,0 +1,235 @@ +/* + drivers/net/tulip/21142.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include + + +static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; +u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; +static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + + + +/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list + of available transceivers. */ +void t21142_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + int next_tick = 60*HZ; + int new_csr6 = 0; + + if (tulip_debug > 2) + printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", + dev->name, csr12, medianame[dev->if_port]); + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + tulip_check_duplex(dev); + next_tick = 60*HZ; + } else if (tp->nwayset) { + /* Don't screw up a negotiated session! */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n", + dev->name, medianame[dev->if_port], csr12); + } else if (tp->medialock) { + ; + } else if (dev->if_port == 3) { + if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, " + "trying NWay.\n", dev->name, csr12); + t21142_start_nway(dev); + next_tick = 3*HZ; + } + } else if ((csr12 & 0x7000) != 0x5000) { + /* Negotiation failed. Search media types. */ + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n", + dev->name, csr12); + if (!(csr12 & 4)) { /* 10mbps link beat good. */ + new_csr6 = 0x82420000; + dev->if_port = 0; + outl(0, ioaddr + CSR13); + outl(0x0003FFFF, ioaddr + CSR14); + outw(t21142_csr15[dev->if_port], ioaddr + CSR15); + outl(t21142_csr13[dev->if_port], ioaddr + CSR13); + } else { + /* Select 100mbps port to check for link beat. */ + new_csr6 = 0x83860000; + dev->if_port = 3; + outl(0, ioaddr + CSR13); + outl(0x0003FF7F, ioaddr + CSR14); + outw(8, ioaddr + CSR15); + outl(1, ioaddr + CSR13); + } + if (tulip_debug > 1) + printk(KERN_INFO"%s: Testing new 21143 media %s.\n", + dev->name, medianame[dev->if_port]); + if (new_csr6 != (tp->csr6 & ~0x00D5)) { + tp->csr6 &= 0x00D5; + tp->csr6 |= new_csr6; + outl(0x0301, ioaddr + CSR12); + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } + next_tick = 3*HZ; + } + + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + + +void t21142_start_nway(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr14 = ((tp->to_advertise & 0x0780) << 9) | + ((tp->to_advertise&0x0020)<<1) | 0xffbf; + + dev->if_port = 0; + tp->nway = tp->mediasense = 1; + tp->nwayset = tp->lpar = 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n", + dev->name, csr14); + outl(0x0001, ioaddr + CSR13); + outl(csr14, ioaddr + CSR14); + tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); + tulip_outl_CSR6(tp, tp->csr6); + if (tp->mtable && tp->mtable->csr15dir) { + outl(tp->mtable->csr15dir, ioaddr + CSR15); + outl(tp->mtable->csr15val, ioaddr + CSR15); + } else + outw(0x0008, ioaddr + CSR15); + outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ +} + + +void t21142_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr12 = inl(ioaddr + CSR12); + + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " + "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14)); + + /* If NWay finished and we have a negotiated partner capability. */ + if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { + int setup_done = 0; + int negotiated = tp->to_advertise & (csr12 >> 16); + tp->lpar = csr12 >> 16; + tp->nwayset = 1; + if (negotiated & 0x0100) dev->if_port = 5; + else if (negotiated & 0x0080) dev->if_port = 3; + else if (negotiated & 0x0040) dev->if_port = 4; + else if (negotiated & 0x0020) dev->if_port = 0; + else { + tp->nwayset = 0; + if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180)) + dev->if_port = 3; + } + tp->full_duplex = (tulip_media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0; + + if (tulip_debug > 1) { + if (tp->nwayset) + printk(KERN_INFO "%s: Switching to %s based on link " + "negotiation %4.4x & %4.4x = %4.4x.\n", + dev->name, medianame[dev->if_port], tp->to_advertise, + tp->lpar, negotiated); + else + printk(KERN_INFO "%s: Autonegotiation failed, using %s," + " link beat status %4.4x.\n", + dev->name, medianame[dev->if_port], csr12); + } + + if (tp->mtable) { + int i; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == dev->if_port) { + tp->cur_index = i; + tulip_select_media(dev, 0); + setup_done = 1; + break; + } + } + if ( ! setup_done) { + tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000; + if (tp->full_duplex) + tp->csr6 |= 0x0200; + outl(1, ioaddr + CSR13); + } +#if 0 /* Restart shouldn't be needed. */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0000); + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", + dev->name, inl(ioaddr + CSR5)); +#endif + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n", + dev->name, tp->csr6, inl(ioaddr + CSR6), + inl(ioaddr + CSR12)); + } else if ((tp->nwayset && (csr5 & 0x08000000) + && (dev->if_port == 3 || dev->if_port == 5) + && (csr12 & 2) == 2) || + (tp->nway && (csr5 & (TPLnkFail)))) { + /* Link blew? Maybe restart NWay. */ + del_timer(&tp->timer); + t21142_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } else if (dev->if_port == 3 || dev->if_port == 5) { + if (tulip_debug > 1) + printk(KERN_INFO"%s: 21143 %s link beat %s.\n", + dev->name, medianame[dev->if_port], + (csr12 & 2) ? "failed" : "good"); + if ((csr12 & 2) && ! tp->medialock) { + del_timer(&tp->timer); + t21142_start_nway(dev); + tp->timer.expires = RUN_AT(3*HZ); + add_timer(&tp->timer); + } + } else if (dev->if_port == 0 || dev->if_port == 4) { + if ((csr12 & 4) == 0) + printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", + dev->name); + } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ + if (tulip_debug) + printk(KERN_INFO"%s: 21143 10mbps sensed media.\n", + dev->name); + dev->if_port = 0; + } else if (tp->nwayset) { + if (tulip_debug) + printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n", + dev->name, medianame[dev->if_port], tp->csr6); + } else { /* 100mbps link beat good. */ + if (tulip_debug) + printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", + dev->name); + dev->if_port = 3; + tp->csr6 = 0x83860000; + outl(0x0003FF7F, ioaddr + CSR14); + outl(0x0301, ioaddr + CSR12); + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } +} + + diff -u --recursive --new-file v2.3.47/linux/drivers/net/tulip/Makefile linux/drivers/net/tulip/Makefile --- v2.3.47/linux/drivers/net/tulip/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tulip/Makefile Mon Feb 21 10:59:36 2000 @@ -0,0 +1,14 @@ +# +# Makefile for the Tulip ethernet driver +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := tulip.o +O_OBJS := 21142.o eeprom.o interrupt.o media.o pnic.o timer.o tulip_core.o +M_OBJS := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.3.47/linux/drivers/net/tulip/eeprom.c linux/drivers/net/tulip/eeprom.c --- v2.3.47/linux/drivers/net/tulip/eeprom.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tulip/eeprom.c Fri Feb 25 15:16:37 2000 @@ -0,0 +1,270 @@ +/* + drivers/net/tulip/eeprom.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include +#include +#include + + + +/* Serial EEPROM section. */ +/* The main routine to parse the very complicated SROM structure. + Search www.digital.com for "21X4 SROM" to get details. + This code is very complex, and will require changes to support + additional cards, so I'll be verbose about what is going on. + */ + +/* Known cards that have old-style EEPROMs. */ +static struct eeprom_fixup eeprom_fixups[] __devinitdata = { + {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, + 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, + {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0903, 0x006D, /* 100baseTx */ + 0x0905, 0x006D, /* 100baseTx-FD */ }}, + {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, + 0x0107, 0x8021, /* 100baseFx */ + 0x0108, 0x8021, /* 100baseFx-FD */ + 0x0100, 0x009E, /* 10baseT */ + 0x0104, 0x009E, /* 10baseT-FD */ + 0x0103, 0x006D, /* 100baseTx */ + 0x0105, 0x006D, /* 100baseTx-FD */ }}, + {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, + 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ + 0x0000, 0x009E, /* 10baseT */ + 0x0004, 0x009E, /* 10baseT-FD */ + 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ + 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, + {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, + 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ + 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ + 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ + 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ + 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ + }}, + {0, 0, 0, 0, {}}}; + + +static const char *block_name[] __devinitdata = { + "21140 non-MII", + "21140 MII PHY", + "21142 Serial PHY", + "21142 MII PHY", + "21143 SYM PHY", + "21143 reset method" +}; + + +void __devinit tulip_parse_eeprom(struct net_device *dev) +{ + /* The last media info list parsed, for multiport boards. */ + static struct mediatable *last_mediatable = NULL; + static unsigned char *last_ee_data = NULL; + static int controller_index = 0; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + unsigned char *ee_data = tp->eeprom; + int i; + + tp->mtable = 0; + /* Detect an old-style (SA only) EEPROM layout: + memcmp(eedata, eedata+16, 8). */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + break; + if (i >= 8) { + if (ee_data[0] == 0xff) { + if (last_mediatable) { + controller_index++; + printk(KERN_INFO "%s: Controller %d of multiport board.\n", + dev->name, controller_index); + tp->mtable = last_mediatable; + ee_data = last_ee_data; + goto subsequent_board; + } else + printk(KERN_INFO "%s: Missing EEPROM, this interface may " + "not work correctly!\n", + dev->name); + return; + } + /* Do a fix-up based on the vendor half of the station address prefix. */ + for (i = 0; eeprom_fixups[i].name; i++) { + if (dev->dev_addr[0] == eeprom_fixups[i].addr0 + && dev->dev_addr[1] == eeprom_fixups[i].addr1 + && dev->dev_addr[2] == eeprom_fixups[i].addr2) { + if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) + i++; /* An Accton EN1207, not an outlaw Maxtech. */ + memcpy(ee_data + 26, eeprom_fixups[i].newtable, + sizeof(eeprom_fixups[i].newtable)); + printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" + " substitute media control info.\n", + dev->name, eeprom_fixups[i].name); + break; + } + } + if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ + printk(KERN_INFO "%s: Old style EEPROM with no media selection " + "information.\n", + dev->name); + return; + } + } + + controller_index = 0; + if (ee_data[19] > 1) { /* Multiport board. */ + last_ee_data = ee_data; + } +subsequent_board: + + if (ee_data[27] == 0) { /* No valid media table. */ + } else if (tp->chip_id == DC21041) { + unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; + int media = get_u16(p); + int count = p[2]; + p += 3; + + printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n", + dev->name, media, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + unsigned char media_code = *p++; + if (media_code & 0x40) + p += 6; + printk(KERN_INFO "%s: 21041 media #%d, %s.\n", + dev->name, media_code & 15, medianame[media_code & 15]); + } + } else { + unsigned char *p = (void *)ee_data + ee_data[27]; + unsigned char csr12dir = 0; + int count, new_advertise = 0; + struct mediatable *mtable; + u16 media = get_u16(p); + + p += 2; + if (tp->flags & CSR12_IN_SROM) + csr12dir = *p++; + count = *p++; + mtable = (struct mediatable *) + kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), + GFP_KERNEL); + if (mtable == NULL) + return; /* Horrible, impossible failure. */ + last_mediatable = tp->mtable = mtable; + mtable->defaultmedia = media; + mtable->leafcount = count; + mtable->csr12dir = csr12dir; + mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; + mtable->csr15dir = mtable->csr15val = 0; + + printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, + media & 0x0800 ? "Autosense" : medianame[media & 15]); + for (i = 0; i < count; i++) { + struct medialeaf *leaf = &mtable->mleaf[i]; + + if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ + leaf->type = 0; + leaf->media = p[0] & 0x3f; + leaf->leafdata = p; + if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ + mtable->has_mii = 1; + p += 4; + } else { + leaf->type = p[1]; + if (p[1] == 0x05) { + mtable->has_reset = i; + leaf->media = p[2] & 0x0f; + } else if (p[1] & 1) { + mtable->has_mii = 1; + leaf->media = 11; + } else { + mtable->has_nonmii = 1; + leaf->media = p[2] & 0x0f; + switch (leaf->media) { + case 0: new_advertise |= 0x0020; break; + case 4: new_advertise |= 0x0040; break; + case 3: new_advertise |= 0x0080; break; + case 5: new_advertise |= 0x0100; break; + case 6: new_advertise |= 0x0200; break; + } + if (p[1] == 2 && leaf->media == 0) { + if (p[2] & 0x40) { + u32 base15 = get_unaligned((u16*)&p[7]); + mtable->csr15dir = + (get_unaligned((u16*)&p[9])<<16) + base15; + mtable->csr15val = + (get_unaligned((u16*)&p[11])<<16) + base15; + } else { + mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; + mtable->csr15val = get_unaligned((u16*)&p[5])<<16; + } + } + } + leaf->leafdata = p + 2; + p += (p[0] & 0x3f) + 1; + } + if (tulip_debug > 1 && leaf->media == 11) { + unsigned char *bp = leaf->leafdata; + printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " + "sequences %d/%d long, capabilities %2.2x %2.2x.\n", + dev->name, bp[0], bp[1], bp[2 + bp[1]*2], + bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); + } + printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " + "by a %s (%d) block.\n", + dev->name, i, medianame[leaf->media], leaf->media, + block_name[leaf->type], leaf->type); + } + if (new_advertise) + tp->to_advertise = new_advertise; + } +} +/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ + +/* Note: this routine returns extra data bits for size detection. */ +int __devinit tulip_read_eeprom(long ioaddr, int location, int addr_len) +{ + int i; + unsigned retval = 0; + long ee_addr = ioaddr + CSR9; + int read_cmd = location | (EE_READ_CMD << addr_len); + + outl(EE_ENB & ~EE_CS, ee_addr); + outl(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 4 + addr_len; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outl(EE_ENB | dataval, ee_addr); + eeprom_delay(); + outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + } + outl(EE_ENB, ee_addr); + + for (i = 16; i > 0; i--) { + outl(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); + outl(EE_ENB, ee_addr); + eeprom_delay(); + } + + /* Terminate the EEPROM access. */ + outl(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + diff -u --recursive --new-file v2.3.47/linux/drivers/net/tulip/interrupt.c linux/drivers/net/tulip/interrupt.c --- v2.3.47/linux/drivers/net/tulip/interrupt.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tulip/interrupt.c Fri Feb 25 15:16:37 2000 @@ -0,0 +1,337 @@ +/* + drivers/net/tulip/interrupt.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include +#include + + +int tulip_rx_copybreak; +int tulip_max_interrupt_work; + + + +static int tulip_refill_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry; + int refilled = 0; + + /* Refill the Rx ring buffers. */ + for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { + entry = tp->dirty_rx % RX_RING_SIZE; + if (tp->rx_skbuff[entry] == NULL) { + struct sk_buff *skb; + skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ); + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail); + refilled++; + } + tp->rx_ring[entry].status = cpu_to_le32(DescOwned); + } + return refilled; +} + + +static int tulip_rx(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry = tp->cur_rx % RX_RING_SIZE; + int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; + int received = 0; + + if (tulip_debug > 4) + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, + tp->rx_ring[entry].status); + /* If we own the next entry, it is a new packet. Send it up. */ + while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { + s32 status = le32_to_cpu(tp->rx_ring[entry].status); + + if (tulip_debug > 5) + printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", + dev->name, entry, status); + if (--rx_work_limit < 0) + break; + if ((status & 0x38008300) != 0x0300) { + if ((status & 0x38000300) != 0x0300) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Oversized Ethernet frame " + "spanned multiple buffers, status %8.8x!\n", + dev->name, status); + tp->stats.rx_length_errors++; + } + } else if (status & RxDescFatalErr) { + /* There was a fatal error. */ + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", + dev->name, status); + tp->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x0890) tp->stats.rx_length_errors++; + if (status & 0x0004) tp->stats.rx_frame_errors++; + if (status & 0x0002) tp->stats.rx_crc_errors++; + if (status & 0x0001) tp->stats.rx_fifo_errors++; + } + } else { + /* Omit the four octet CRC from the length. */ + short pkt_len = ((status >> 16) & 0x7ff) - 4; + struct sk_buff *skb; + +#ifndef final_version + if (pkt_len > 1518) { + printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", + dev->name, pkt_len, pkt_len); + pkt_len = 1518; + tp->stats.rx_length_errors++; + } +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < tulip_rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ +#if ! defined(__alpha__) + eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail, + pkt_len); +#endif + } else { /* Pass up the skb already on the Rx ring. */ + char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len); + tp->rx_skbuff[entry] = NULL; +#ifndef final_version + if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in tulip_rx: %p vs. %p / %p.\n", + dev->name, + le32desc_to_virt(tp->rx_ring[entry].buffer1), + skb->head, temp); +#endif + } + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + tp->stats.rx_packets++; + tp->stats.rx_bytes += pkt_len; + } + received++; + entry = (++tp->cur_rx) % RX_RING_SIZE; + } + + return received; +} + + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr5; + int entry; + int missed; + int rx = 0; + int tx = 0; + int oi = 0; + int maxrx = RX_RING_SIZE; + int maxtx = TX_RING_SIZE; + int maxoi = TX_RING_SIZE; + int work_count = tulip_max_interrupt_work; + + tp->nir++; + + do { + csr5 = inl(ioaddr + CSR5); + /* Acknowledge all of the current interrupt sources ASAP. */ + outl(csr5 & 0x0001ffff, ioaddr + CSR5); + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + dev->name, csr5, inl(dev->base_addr + CSR5)); + + if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) + break; + + if (csr5 & (RxIntr | RxNoBuf)) { + rx += tulip_rx(dev); + tulip_refill_rx(dev); + } + + if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { + unsigned int dirty_tx; + + spin_lock(&tp->lock); + + for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; + dirty_tx++) { + int entry = dirty_tx % TX_RING_SIZE; + int status = le32_to_cpu(tp->tx_ring[entry].status); + + if (status < 0) + break; /* It still has not been Txed */ + /* Check for Rx filter setup frames. */ + if (tp->tx_skbuff[entry] == NULL) + continue; + + if (status & 0x8000) { + /* There was an major error, log it. */ +#ifndef final_version + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, status); +#endif + tp->stats.tx_errors++; + if (status & 0x4104) tp->stats.tx_aborted_errors++; + if (status & 0x0C00) tp->stats.tx_carrier_errors++; + if (status & 0x0200) tp->stats.tx_window_errors++; + if (status & 0x0002) tp->stats.tx_fifo_errors++; + if ((status & 0x0080) && tp->full_duplex == 0) + tp->stats.tx_heartbeat_errors++; +#ifdef ETHER_STATS + if (status & 0x0100) tp->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + if (status & 0x0001) tp->stats.tx_deferred++; +#endif + tp->stats.tx_bytes += tp->tx_skbuff[entry]->len; + tp->stats.collisions += (status >> 3) & 15; + tp->stats.tx_packets++; + } + + /* Free the original skb. */ + dev_kfree_skb_irq(tp->tx_skbuff[entry]); + tp->tx_skbuff[entry] = 0; + tx++; + } + +#ifndef final_version + if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { + printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, tp->cur_tx, tp->tx_full); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { + /* The ring is no longer full, clear tbusy. */ + tp->tx_full = 0; + netif_wake_queue(dev); + } + + tp->dirty_tx = dirty_tx; + if (csr5 & TxDied) { + if (tulip_debug > 2) + printk(KERN_WARNING "%s: The transmitter stopped." + " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", + dev->name, csr5, inl(ioaddr + CSR6), tp->csr6); + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } + spin_unlock(&tp->lock); + } + + /* Log errors. */ + if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ + if (csr5 == 0xffffffff) + break; + if (csr5 & TxJabber) tp->stats.tx_errors++; + if (csr5 & TxFIFOUnderflow) { + if ((tp->csr6 & 0xC000) != 0xC000) + tp->csr6 += 0x4000; /* Bump up the Tx threshold */ + else + tp->csr6 |= 0x00200000; /* Store-n-forward. */ + /* Restart the transmit process. */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + outl(0, ioaddr + CSR1); + } + if (csr5 & RxDied) { /* Missed a Rx frame. */ + tp->stats.rx_errors++; + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + } + if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { + if (tp->link_change) + (tp->link_change)(dev, csr5); + } + if (csr5 & SytemError) { + printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir); + } + /* Clear all error sources, included undocumented ones! */ + outl(0x0800f7ba, ioaddr + CSR5); + oi++; + } + if (csr5 & TimerInt) { +#if 0 + if (tulip_debug > 2) + printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", + dev->name, csr5); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); +#endif + tp->ttimer = 0; + oi++; + } + if (tx > maxtx || rx > maxrx || oi > maxoi) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Too much work during an interrupt, " + "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi); + /* Acknowledge all interrupt sources. */ +#if 0 + /* Clear all interrupting sources, set timer to re-enable. */ + outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt, + ioaddr + CSR7); + outl(12, ioaddr + CSR11); + tp->ttimer = 1; +#endif + break; + } + } while (work_count-- > 0); + + tulip_refill_rx(dev); + + /* check if we card is in suspend mode */ + entry = tp->dirty_rx % RX_RING_SIZE; + if (tp->rx_skbuff[entry] == NULL) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); + if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) { + if (tulip_debug > 1) + printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); + outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, + ioaddr + CSR7); + outl(TimerInt, ioaddr + CSR5); + outl(12, ioaddr + CSR11); + tp->ttimer = 1; + } + } + + if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) { + tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; + } + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", + dev->name, inl(ioaddr + CSR5)); + +} + diff -u --recursive --new-file v2.3.47/linux/drivers/net/tulip/media.c linux/drivers/net/tulip/media.c --- v2.3.47/linux/drivers/net/tulip/media.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tulip/media.c Fri Feb 25 15:16:37 2000 @@ -0,0 +1,403 @@ +/* + drivers/net/tulip/media.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include + + +/* This is a mysterious value that can be written to CSR11 in the 21040 (only) + to support a pre-NWay full-duplex signaling mechanism using short frames. + No one knows what it should be, but if left at its default value some + 10base2(!) packets trigger a full-duplex-request interrupt. */ +#define FULL_DUPLEX_MAGIC 0x6969 + + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. */ + +int tulip_mdio_read(struct net_device *dev, int phy_id, int location) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int retval = 0; + long ioaddr = dev->base_addr; + long mdio_addr = ioaddr + CSR9; + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); + inl(ioaddr + 0xA0); + inl(ioaddr + 0xA0); + while (--i > 0) + if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) + return retval & 0xffff; + return 0xffff; + } + + if (tp->chip_id == COMET) { + if (phy_id == 1) { + if (location < 7) + return inl(ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + return inl(ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + return inl(ioaddr + 0xD4 + ((location-29)<<2)); + } + return 0xffff; + } + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + return (retval>>1) & 0xffff; +} + +void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + long ioaddr = dev->base_addr; + long mdio_addr = ioaddr + CSR9; + + if (tp->chip_id == LC82C168) { + int i = 1000; + outl(cmd, ioaddr + 0xA0); + do + if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) + break; + while (--i > 0); + return; + } + + if (tp->chip_id == COMET) { + if (phy_id != 1) + return; + if (location < 7) + outl(value, ioaddr + 0xB4 + (location<<2)); + else if (location == 17) + outl(value, ioaddr + 0xD0); + else if (location >= 29 && location <= 31) + outl(value, ioaddr + 0xD4 + ((location-29)<<2)); + return; + } + + /* Establish sync by sending 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + outl(MDIO_ENB | dataval, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } +} + + +/* Set up the transceiver control registers for the selected media type. */ +void tulip_select_media(struct net_device *dev, int startup) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct mediatable *mtable = tp->mtable; + u32 new_csr6; + int i; + + if (mtable) { + struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; + unsigned char *p = mleaf->leafdata; + switch (mleaf->type) { + case 0: /* 21140 non-MII xcvr. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver" + " with control setting %2.2x.\n", + dev->name, p[1]); + dev->if_port = p[0]; + if (startup) + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + outl(p[1], ioaddr + CSR12); + new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); + break; + case 2: case 4: { + u16 setup[5]; + u32 csr13val, csr14val, csr15dir, csr15val; + for (i = 0; i < 5; i++) + setup[i] = get_u16(&p[i*2 + 1]); + + dev->if_port = p[0] & 15; + if (tulip_media_cap[dev->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + + if (startup && mtable->has_reset) { + struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; + unsigned char *rst = rleaf->leafdata; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Resetting the transceiver.\n", + dev->name); + for (i = 0; i < rst[0]; i++) + outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control " + "%4.4x/%4.4x.\n", + dev->name, medianame[dev->if_port], setup[0], setup[1]); + if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ + csr13val = setup[0]; + csr14val = setup[1]; + csr15dir = (setup[3]<<16) | setup[2]; + csr15val = (setup[4]<<16) | setup[2]; + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + outl(csr13val, ioaddr + CSR13); + } else { + csr13val = 1; + csr14val = 0x0003FF7F; + csr15dir = (setup[0]<<16) | 0x0008; + csr15val = (setup[1]<<16) | 0x0008; + if (dev->if_port <= 4) + csr14val = t21142_csr14[dev->if_port]; + if (startup) { + outl(0, ioaddr + CSR13); + outl(csr14val, ioaddr + CSR14); + } + outl(csr15dir, ioaddr + CSR15); /* Direction */ + outl(csr15val, ioaddr + CSR15); /* Data */ + if (startup) outl(csr13val, ioaddr + CSR13); + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n", + dev->name, csr15dir, csr15val); + if (mleaf->type == 4) + new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); + else + new_csr6 = 0x82420000; + break; + } + case 1: case 3: { + int phy_num = p[0]; + int init_length = p[1]; + u16 *misc_info; + u16 to_advertise; + + dev->if_port = 11; + new_csr6 = 0x020E0000; + if (mleaf->type == 3) { /* 21142 */ + u16 *init_sequence = (u16*)(p+2); + u16 *reset_sequence = &((u16*)(p+3))[init_length]; + int reset_length = p[2 + init_length*2]; + misc_info = reset_sequence + reset_length; + if (startup) + for (i = 0; i < reset_length; i++) + outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); + for (i = 0; i < init_length; i++) + outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); + } else { + u8 *init_sequence = p + 2; + u8 *reset_sequence = p + 3 + init_length; + int reset_length = p[2 + init_length]; + misc_info = (u16*)(reset_sequence + reset_length); + if (startup) { + outl(mtable->csr12dir | 0x100, ioaddr + CSR12); + for (i = 0; i < reset_length; i++) + outl(reset_sequence[i], ioaddr + CSR12); + } + for (i = 0; i < init_length; i++) + outl(init_sequence[i], ioaddr + CSR12); + } + to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1; + tp->advertising[phy_num] = to_advertise; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n", + dev->name, to_advertise, phy_num, tp->phys[phy_num]); + /* Bogus: put in by a committee? */ + tulip_mdio_write(dev, tp->phys[phy_num], 4, to_advertise); + break; + } + default: + printk(KERN_DEBUG "%s: Invalid media table selection %d.\n", + dev->name, mleaf->type); + new_csr6 = 0x020E0000; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12) & 0xff); + } else if (tp->chip_id == DC21041) { + int port = dev->if_port <= 4 ? dev->if_port : 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", + dev->name, medianame[port == 3 ? 12: port], + inl(ioaddr + CSR12)); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + outl(t21041_csr14[port], ioaddr + CSR14); + outl(t21041_csr15[port], ioaddr + CSR15); + outl(t21041_csr13[port], ioaddr + CSR13); + new_csr6 = 0x80020000; + } else if (tp->chip_id == LC82C168) { + if (startup && ! tp->medialock) + dev->if_port = tp->mii_cnt ? 11 : 0; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n", + dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]); + if (tp->mii_cnt) { + new_csr6 = 0x810C0000; + outl(0x0001, ioaddr + CSR15); + outl(0x0201B07A, ioaddr + 0xB8); + } else if (startup) { + /* Start with 10mbps to do autonegotiation. */ + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x0001B078, ioaddr + 0xB8); + outl(0x0201B078, ioaddr + 0xB8); + } else if (dev->if_port == 3 || dev->if_port == 5) { + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + /* Trigger autonegotiation. */ + outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8); + } else { + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + } else if (tp->chip_id == DC21040) { /* 21040 */ + /* Turn on the xcvr interface. */ + int csr12 = inl(ioaddr + CSR12); + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", + dev->name, medianame[dev->if_port], csr12); + if (tulip_media_cap[dev->if_port] & MediaAlwaysFD) + tp->full_duplex = 1; + new_csr6 = 0x20000; + /* Set the full duplux match frame. */ + outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); + outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ + if (t21040_csr13[dev->if_port] & 8) { + outl(0x0705, ioaddr + CSR14); + outl(0x0006, ioaddr + CSR15); + } else { + outl(0xffff, ioaddr + CSR14); + outl(0x0000, ioaddr + CSR15); + } + outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13); + } else { /* Unknown chip type with no media table. */ + if (tp->default_port == 0) + dev->if_port = tp->mii_cnt ? 11 : 3; + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + new_csr6 = 0x020E0000; + } else if (tulip_media_cap[dev->if_port] & MediaIsFx) { + new_csr6 = 0x028600000; + } else + new_csr6 = 0x038600000; + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No media description table, assuming " + "%s transceiver, CSR12 %2.2x.\n", + dev->name, medianame[dev->if_port], + inl(ioaddr + CSR12)); + } + + tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); + return; +} + +/* + Check the MII negotiated duplex, and change the CSR6 setting if + required. + Return 0 if everything is OK. + Return < 0 if the transceiver is missing or has no link beat. + */ +int tulip_check_duplex(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int mii_reg1, mii_reg5, negotiated, duplex; + + if (tp->full_duplex_lock) + return 0; + mii_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); + mii_reg5 = tulip_mdio_read(dev, tp->phys[0], 5); + if (tulip_debug > 1) + printk(KERN_INFO "%s: MII status %4.4x, Link partner report " + "%4.4x.\n", dev->name, mii_reg1, mii_reg5); + if (mii_reg1 == 0xffff) + return -2; + if ((mii_reg1 & 0x0004) == 0) { + int new_reg1 = tulip_mdio_read(dev, tp->phys[0], 1); + if ((new_reg1 & 0x0004) == 0) { + if (tulip_debug > 1) + printk(KERN_INFO "%s: No link beat on the MII interface," + " status %4.4x.\n", dev->name, new_reg1); + return -1; + } + } + negotiated = mii_reg5 & tp->advertising[0]; + duplex = ((negotiated & 0x0300) == 0x0100 + || (negotiated & 0x00C0) == 0x0040); + /* 100baseTx-FD or 10T-FD, but not 100-HD */ + if (tp->full_duplex != duplex) { + tp->full_duplex = duplex; + if (negotiated & 0x038) /* 100mbps. */ + tp->csr6 &= ~0x00400000; + if (tp->full_duplex) tp->csr6 |= 0x0200; + else tp->csr6 &= ~0x0200; + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + if (tulip_debug > 0) + printk(KERN_INFO "%s: Setting %s-duplex based on MII" + "#%d link partner capability of %4.4x.\n", + dev->name, tp->full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + return 1; + } + return 0; +} + diff -u --recursive --new-file v2.3.47/linux/drivers/net/tulip/pnic.c linux/drivers/net/tulip/pnic.c --- v2.3.47/linux/drivers/net/tulip/pnic.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tulip/pnic.c Fri Feb 25 15:16:37 2000 @@ -0,0 +1,146 @@ +/* + drivers/net/tulip/pnic.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include +#include "tulip.h" +#include + + +void pnic_do_nway(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u32 phy_reg = inl(ioaddr + 0xB8); + u32 new_csr6 = tp->csr6 & ~0x40C40200; + + if (phy_reg & 0x78000000) { /* Ignore baseT4 */ + if (phy_reg & 0x20000000) dev->if_port = 5; + else if (phy_reg & 0x40000000) dev->if_port = 3; + else if (phy_reg & 0x10000000) dev->if_port = 4; + else if (phy_reg & 0x08000000) dev->if_port = 0; + tp->nwayset = 1; + new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000; + outl(0x32 | (dev->if_port & 1), ioaddr + CSR12); + if (dev->if_port & 1) + outl(0x1F868, ioaddr + 0xB8); + if (phy_reg & 0x30000000) { + tp->full_duplex = 1; + new_csr6 |= 0x00000200; + } + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n", + dev->name, phy_reg, medianame[dev->if_port]); + if (tp->csr6 != new_csr6) { + tp->csr6 = new_csr6; + /* Restart Tx */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + dev->trans_start = jiffies; + } + } +} + + +void pnic_lnk_change(struct net_device *dev, int csr5) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int phy_reg = inl(ioaddr + 0xB8); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n", + dev->name, phy_reg, csr5); + if (inl(ioaddr + CSR5) & TPLnkFail) { + outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); + if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { + tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); + tulip_outl_CSR6(tp, tp->csr6); + outl(0x30, ioaddr + CSR12); + outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ + dev->trans_start = jiffies; + } + } else if (inl(ioaddr + CSR5) & TPLnkPass) { + pnic_do_nway(dev); + outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7); + } +} + + +void pnic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + if (tulip_check_duplex(dev) > 0) + next_tick = 3*HZ; + } else { + int csr12 = inl(ioaddr + CSR12); + int new_csr6 = tp->csr6 & ~0x40C40200; + int phy_reg = inl(ioaddr + 0xB8); + int csr5 = inl(ioaddr + CSR5); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s " + "CSR5 %8.8x.\n", + dev->name, phy_reg, medianame[dev->if_port], csr5); + if (phy_reg & 0x04000000) { /* Remote link fault */ + outl(0x0201F078, ioaddr + 0xB8); + next_tick = 1*HZ; + tp->nwayset = 0; + } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */ + pnic_do_nway(dev); + next_tick = 60*HZ; + } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " + "CSR5 %8.8x, PHY %3.3x.\n", + dev->name, medianame[dev->if_port], csr12, + inl(ioaddr + CSR5), inl(ioaddr + 0xB8)); + next_tick = 3*HZ; + if (tp->medialock) { + } else if (tp->nwayset && (dev->if_port & 1)) { + next_tick = 1*HZ; + } else if (dev->if_port == 0) { + dev->if_port = 3; + outl(0x33, ioaddr + CSR12); + new_csr6 = 0x01860000; + outl(0x1F868, ioaddr + 0xB8); + } else { + dev->if_port = 0; + outl(0x32, ioaddr + CSR12); + new_csr6 = 0x00420000; + outl(0x1F078, ioaddr + 0xB8); + } + if (tp->csr6 != new_csr6) { + tp->csr6 = new_csr6; + /* Restart Tx */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + dev->trans_start = jiffies; + if (tulip_debug > 1) + printk(KERN_INFO "%s: Changing PNIC configuration to %s " + "%s-duplex, CSR6 %8.8x.\n", + dev->name, medianame[dev->if_port], + tp->full_duplex ? "full" : "half", new_csr6); + } + } + } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + diff -u --recursive --new-file v2.3.47/linux/drivers/net/tulip/timer.c linux/drivers/net/tulip/timer.c --- v2.3.47/linux/drivers/net/tulip/timer.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tulip/timer.c Fri Feb 25 15:16:37 2000 @@ -0,0 +1,208 @@ +/* + drivers/net/tulip/timer.c + + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please refer to Documentation/networking/tulip.txt for more + information on this driver. + +*/ + +#include "tulip.h" +#include + + +void tulip_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u32 csr12 = inl(ioaddr + CSR12); + int next_tick = 2*HZ; + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode" + " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n", + dev->name, medianame[dev->if_port], inl(ioaddr + CSR5), + inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13), + inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + } + switch (tp->chip_id) { + case DC21040: + if (!tp->medialock && csr12 & 0x0002) { /* Network error */ + printk(KERN_INFO "%s: No link beat found.\n", + dev->name); + dev->if_port = (dev->if_port == 2 ? 0 : 2); + tulip_select_media(dev, 0); + dev->trans_start = jiffies; + } + break; + case DC21041: + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", + dev->name, csr12); + if (tp->medialock) break; + switch (dev->if_port) { + case 0: case 3: case 4: + if (csr12 & 0x0004) { /*LnkFail */ + /* 10baseT is dead. Check for activity on alternate port. */ + tp->mediasense = 1; + if (csr12 & 0x0200) + dev->if_port = 2; + else + dev->if_port = 1; + printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", + dev->name, medianame[dev->if_port]); + outl(0, ioaddr + CSR13); /* Reset */ + outl(t21041_csr14[dev->if_port], ioaddr + CSR14); + outl(t21041_csr15[dev->if_port], ioaddr + CSR15); + outl(t21041_csr13[dev->if_port], ioaddr + CSR13); + next_tick = 10*HZ; /* 2.4 sec. */ + } else + next_tick = 30*HZ; + break; + case 1: /* 10base2 */ + case 2: /* AUI */ + if (csr12 & 0x0100) { + next_tick = (30*HZ); /* 30 sec. */ + tp->mediasense = 0; + } else if ((csr12 & 0x0004) == 0) { + printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", + dev->name); + dev->if_port = 0; + tulip_select_media(dev, 0); + next_tick = (24*HZ)/10; /* 2.4 sec. */ + } else if (tp->mediasense || (csr12 & 0x0002)) { + dev->if_port = 3 - dev->if_port; /* Swap ports. */ + tulip_select_media(dev, 0); + next_tick = 20*HZ; + } else { + next_tick = 20*HZ; + } + break; + } + break; + case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { + struct medialeaf *mleaf; + unsigned char *p; + if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ + /* Not much that can be done. + Assume this a generic MII or SYM transceiver. */ + next_tick = 60*HZ; + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " + "CSR12 0x%2.2x.\n", + dev->name, inl(ioaddr + CSR6), csr12 & 0xff); + break; + } + mleaf = &tp->mtable->mleaf[tp->cur_index]; + p = mleaf->leafdata; + switch (mleaf->type) { + case 0: case 4: { + /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */ + int offset = mleaf->type == 4 ? 5 : 2; + s8 bitnum = p[offset]; + if (p[offset+1] & 0x80) { + if (tulip_debug > 1) + printk(KERN_DEBUG"%s: Transceiver monitor tick " + "CSR12=%#2.2x, no media sense.\n", + dev->name, csr12); + if (mleaf->type == 4) { + if (mleaf->media == 3 && (csr12 & 0x02)) + goto select_next_media; + } + break; + } + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x" + " bit %d is %d, expecting %d.\n", + dev->name, csr12, (bitnum >> 1) & 7, + (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, + (bitnum >= 0)); + /* Check that the specified bit has the proper value. */ + if ((bitnum < 0) != + ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, + medianame[mleaf->media]); + if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ + goto actually_mii; + break; + } + if (tp->medialock) + break; + select_next_media: + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + dev->if_port = tp->mtable->mleaf[tp->cur_index].media; + if (tulip_media_cap[dev->if_port] & MediaIsFD) + goto select_next_media; /* Skip FD entries. */ + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: No link beat on media %s," + " trying transceiver type %s.\n", + dev->name, medianame[mleaf->media & 15], + medianame[tp->mtable->mleaf[tp->cur_index].media]); + tulip_select_media(dev, 0); + /* Restart the transmit process. */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + next_tick = (24*HZ)/10; + break; + } + case 1: case 3: /* 21140, 21142 MII */ + actually_mii: + tulip_check_duplex(dev); + next_tick = 60*HZ; + break; + case 2: /* 21142 serial block has no link beat. */ + default: + break; + } + } + break; + } + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + + +void mxic_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 3) { + printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name, + inl(ioaddr + CSR12)); + } + if (next_tick) { + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); + } +} + + +void comet_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 60*HZ; + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability " + "%4.4x.\n", + dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8)); + tp->timer.expires = RUN_AT(next_tick); + add_timer(&tp->timer); +} + diff -u --recursive --new-file v2.3.47/linux/drivers/net/tulip/tulip.h linux/drivers/net/tulip/tulip.h --- v2.3.47/linux/drivers/net/tulip/tulip.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tulip/tulip.h Fri Feb 25 15:16:37 2000 @@ -0,0 +1,342 @@ +/* + drivers/net/tulip/tulip.h + + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + +*/ + +#ifndef __NET_TULIP_H__ +#define __NET_TULIP_H__ + +#include +#include +#include +#include +#include + + +struct tulip_chip_table { + char *chip_name; + int io_size; + int valid_intrs; /* CSR7 interrupt enable settings */ + int flags; + void (*media_timer) (unsigned long data); +}; + + +enum tbl_flag { + HAS_MII = 1, + HAS_MEDIA_TABLE = 2, + CSR12_IN_SROM = 4, + ALWAYS_CHECK_MII = 8, + HAS_ACPI = 0x10, + MC_HASH_ONLY = 0x20, /* Hash-only multicast filter. */ + HAS_PNICNWAY = 0x80, + HAS_NWAY143 = 0x40, /* Uses internal NWay xcvr. */ + HAS_8023X = 0x100, +}; + + +/* chip types. careful! order is VERY IMPORTANT here, as these + * are used throughout the driver as indices into arrays */ +/* Note 21142 == 21143. */ +enum chips { + DC21040 = 0, + DC21041 = 1, + DC21140 = 2, + DC21142 = 3, DC21143 = 3, + LC82C168, + NGMC169, + MX98713, + MX98715, + MX98725, + AX88140, + PNIC2, + COMET, + COMPEX9881, + I21145, + X3201_3, +}; + + +enum MediaIs { + MediaIsFD = 1, + MediaAlwaysFD = 2, + MediaIsMII = 4, + MediaIsFx = 8, + MediaIs100 = 16 +}; + + +/* Offsets to the Command and Status Registers, "CSRs". All accesses + must be longword instructions and quadword aligned. */ +enum tulip_offsets { + CSR0 = 0, + CSR1 = 0x08, + CSR2 = 0x10, + CSR3 = 0x18, + CSR4 = 0x20, + CSR5 = 0x28, + CSR6 = 0x30, + CSR7 = 0x38, + CSR8 = 0x40, + CSR9 = 0x48, + CSR10 = 0x50, + CSR11 = 0x58, + CSR12 = 0x60, + CSR13 = 0x68, + CSR14 = 0x70, + CSR15 = 0x78 +}; + + +/* The bits in the CSR5 status registers, mostly interrupt sources. */ +enum status_bits { + TimerInt = 0x800, + SytemError = 0x2000, + TPLnkFail = 0x1000, + TPLnkPass = 0x10, + NormalIntr = 0x10000, + AbnormalIntr = 0x8000, + RxJabber = 0x200, + RxDied = 0x100, + RxNoBuf = 0x80, + RxIntr = 0x40, + TxFIFOUnderflow = 0x20, + TxJabber = 0x08, + TxNoBuf = 0x04, + TxDied = 0x02, + TxIntr = 0x01, +}; + + +/* The Tulip Rx and Tx buffer descriptors. */ +struct tulip_rx_desc { + s32 status; + s32 length; + u32 buffer1; + u32 buffer2; +}; + + +struct tulip_tx_desc { + s32 status; + s32 length; + u32 buffer1; + u32 buffer2; /* We use only buffer 1. */ +}; + + +enum desc_status_bits { + DescOwned = 0x80000000, + RxDescFatalErr = 0x8000, + RxWholePkt = 0x0300, +}; + + +/* Keep the ring sizes a power of two for efficiency. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define RX_RING_SIZE 32 + + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */ + + +/* Ring-wrap flag in length field, use for last ring entry. + 0x01000000 means chain on buffer2 address, + 0x02000000 means use the ring start address in CSR2/3. + Note: Some work-alike chips do not function correctly in chained mode. + The ASIX chip works only in chained mode. + Thus we indicates ring mode, but always write the 'next' field for + chained mode as well. +*/ +#define DESC_RING_WRAP 0x02000000 + + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ +#define EE_ENB (0x4800 | EE_CS) + +/* Delay between EEPROM clock transitions. + Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. + We add a bus turn-around to insure that this remains true. */ +#define eeprom_delay() inl(ee_addr) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_READ_CMD (6) + +#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ + + +/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back PCI I/O cycles, but we insert a delay to avoid + "overclocking" issues or future 66Mhz PCI. */ +#define mdio_delay() inl(mdio_addr) + +/* Read and write the MII registers using software-generated serial + MDIO protocol. It is just different enough from the EEPROM protocol + to not share code. The maxium data clock rate is 2.5 Mhz. */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 + + +#define RUN_AT(x) (jiffies + (x)) + + +#if defined(__i386__) /* AKA get_unaligned() */ +#define get_u16(ptr) (*(u16 *)(ptr)) +#else +#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) +#endif + + +/* Condensed operations for readability. */ +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + + +struct medialeaf { + u8 type; + u8 media; + unsigned char *leafdata; +}; + + +struct mediatable { + u16 defaultmedia; + u8 leafcount; + u8 csr12dir; /* General purpose pin directions. */ + unsigned has_mii:1; + unsigned has_nonmii:1; + unsigned has_reset:6; + u32 csr15dir; + u32 csr15val; /* 21143 NWay setting. */ + struct medialeaf mleaf[0]; +}; + + +struct mediainfo { + struct mediainfo *next; + int info_type; + int index; + unsigned char *info; +}; + + +struct tulip_private { + const char *product_name; + struct net_device *next_module; + struct tulip_rx_desc rx_ring[RX_RING_SIZE]; + struct tulip_tx_desc tx_ring[TX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + char *rx_buffs; /* Address of temporary Rx buffers. */ + u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */ + int chip_id; + int revision; + int flags; + struct net_device_stats stats; + struct timer_list timer; /* Media selection timer. */ + spinlock_t lock; + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int full_duplex_lock:1; + unsigned int fake_addr:1; /* Multiport board faked address. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + unsigned int media2:4; /* Secondary monitored media port. */ + unsigned int medialock:1; /* Don't sense media type. */ + unsigned int mediasense:1; /* Media sensing in progress. */ + unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */ + unsigned int csr0; /* CSR0 setting. */ + unsigned int csr6; /* Current CSR6 control settings. */ + unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ + void (*link_change) (struct net_device * dev, int csr5); + u16 to_advertise; /* NWay capabilities advertised. */ + u16 lpar; /* 21143 Link partner ability. */ + u16 advertising[4]; + signed char phys[4], mii_cnt; /* MII device addresses. */ + struct mediatable *mtable; + int cur_index; /* Current media index. */ + int saved_if_port; + struct pci_dev *pdev; + int ttimer; + int susp_rx; + unsigned long nir; + unsigned long base_addr; + int pad0, pad1; /* Used for 8-byte alignment */ +}; + + +struct eeprom_fixup { + char *name; + unsigned char addr0; + unsigned char addr1; + unsigned char addr2; + u16 newtable[32]; /* Max length below. */ +}; + + +/* 21142.c */ +extern u16 t21142_csr14[]; +void t21142_timer(unsigned long data); +void t21142_start_nway(struct net_device *dev); +void t21142_lnk_change(struct net_device *dev, int csr5); + +/* eeprom.c */ +void tulip_parse_eeprom(struct net_device *dev); +int tulip_read_eeprom(long ioaddr, int location, int addr_len); + +/* interrupt.c */ +extern int tulip_max_interrupt_work; +extern int tulip_rx_copybreak; +void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); + +/* media.c */ +int tulip_mdio_read(struct net_device *dev, int phy_id, int location); +void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value); +void tulip_select_media(struct net_device *dev, int startup); +int tulip_check_duplex(struct net_device *dev); + +/* pnic.c */ +void pnic_do_nway(struct net_device *dev); +void pnic_lnk_change(struct net_device *dev, int csr5); +void pnic_timer(unsigned long data); + +/* timer.c */ +void tulip_timer(unsigned long data); +void mxic_timer(unsigned long data); +void comet_timer(unsigned long data); + +/* tulip_core.c */ +extern int tulip_debug; +extern const char * const medianame[]; +extern const char tulip_media_cap[]; +extern struct tulip_chip_table tulip_tbl[]; +extern u8 t21040_csr13[]; +extern u16 t21041_csr13[]; +extern u16 t21041_csr14[]; +extern u16 t21041_csr15[]; +void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6); + + +#endif /* __NET_TULIP_H__ */ diff -u --recursive --new-file v2.3.47/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.3.47/linux/drivers/net/tulip/tulip_core.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tulip/tulip_core.c Fri Feb 25 17:38:43 2000 @@ -0,0 +1,1391 @@ +/* tulip_core.c: A DEC 21040-family ethernet driver for Linux. */ + +/* + Maintained by Jeff Garzik + Copyright 2000 The Linux Kernel Team + Written/copyright 1994-1999 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Please read Documentation/networking/tulip.txt for more + information. + + For this specific driver variant please use linux-kernel for + bug reports. + + Additional information available at + http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html + +*/ + +static const char version[] = "Linux Tulip driver version 0.9.3 (Feb 23, 2000)\n"; + +#include +#include "tulip.h" +#include +#include +#include +#include +#include +#include + + +/* A few user-configurable values. */ + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 25; + +#define MAX_UNITS 8 +/* Used to pass the full-duplex flag, etc. */ +static int full_duplex[MAX_UNITS] = {0, }; +static int options[MAX_UNITS] = {0, }; +static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */ + +/* The possible media types that can be set in options[] are: */ +const char * const medianame[] = { + "10baseT", "10base2", "AUI", "100baseTx", + "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", + "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", + "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", +}; + +/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ +#ifdef __alpha__ +static int rx_copybreak = 1518; +#else +static int rx_copybreak = 100; +#endif + +/* + Set the bus performance register. + Typical: Set 16 longword cache alignment, no burst limit. + Cache alignment bits 15:14 Burst length 13:8 + 0000 No alignment 0x00000000 unlimited 0800 8 longwords + 4000 8 longwords 0100 1 longword 1000 16 longwords + 8000 16 longwords 0200 2 longwords 2000 32 longwords + C000 32 longwords 0400 4 longwords + Warning: many older 486 systems are broken and require setting 0x00A04800 + 8 longword cache alignment, 8 longword burst. + ToDo: Non-Intel setting could be better. +*/ + +#if defined(__alpha__) +static int csr0 = 0x01A00000 | 0xE000; +#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__) +static int csr0 = 0x01A00000 | 0x8000; +#else +#warning Processor architecture undefined! +static int csr0 = 0x00A00000 | 0x4800; +#endif + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) + + +/* Kernel compatibility defines, some common to David Hind's PCMCIA package. + This is only in the support-all-kernels source code. */ + +MODULE_AUTHOR("The Linux Kernel Team"); +MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); +MODULE_PARM(tulip_debug, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(csr0, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +#define TULIP_MODULE_NAME "tulip" +#define PFX TULIP_MODULE_NAME ": " + +#ifdef TULIP_DEBUG +int tulip_debug = TULIP_DEBUG; +#else +int tulip_debug = 1; +#endif + + + +/* + * This table use during operation for capabilities and media timer. + * + * It is indexed via the values in 'enum chips' + */ + +struct tulip_chip_table tulip_tbl[] = { + { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, + { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer }, + { "Digital DS21140 Tulip", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, + { "Digital DS21143 Tulip", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, + t21142_timer }, + { "Lite-On 82c168 PNIC", 256, 0x0001ebef, + HAS_MII | HAS_PNICNWAY, pnic_timer }, + { "NETGEAR NGMC169 MAC", 256, 0x0001ebef, + HAS_MII | HAS_PNICNWAY, pnic_timer }, + { "Macronix 98713 PMAC", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + { "Macronix 98715 PMAC", 256, 0x0001ebef, + HAS_MEDIA_TABLE, mxic_timer }, + { "Macronix 98725 PMAC", 256, 0x0001ebef, + HAS_MEDIA_TABLE, mxic_timer }, + { "ASIX AX88140", 128, 0x0001fbff, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, + { "Lite-On PNIC-II", 256, 0x0801fbff, + HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer }, + { "ADMtek Comet", 256, 0x0001abef, + MC_HASH_ONLY, comet_timer }, + { "Compex 9881 PMAC", 128, 0x0001ebef, + HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, + { "Intel DS21145 Tulip", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143, + t21142_timer }, + { "Xircom tulip work-alike", 128, 0x0801fbff, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, + t21142_timer }, + {0}, +}; + + +static struct pci_device_id tulip_pci_tbl[] __devinitdata = { + { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 }, + { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 }, + { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, + { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 }, + { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, + { 0x1385, 0xf004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NGMC169 }, + { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, + { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, + { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, + { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, + { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, + { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, + { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, + { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, + {0}, +}; +MODULE_DEVICE_TABLE(pci,tulip_pci_tbl); + + +/* A full-duplex map for media types. */ +const char tulip_media_cap[] = +{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; +u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; + +/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ +u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; +u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; +u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; + + +static void tulip_tx_timeout(struct net_device *dev); +static void tulip_init_ring(struct net_device *dev); +static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int tulip_open(struct net_device *dev); +static int tulip_close(struct net_device *dev); +static void tulip_up(struct net_device *dev); +static void tulip_down(struct net_device *dev); +static struct net_device_stats *tulip_get_stats(struct net_device *dev); +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void set_rx_mode(struct net_device *dev); + + +/* The Xircom cards are picky about when certain bits in CSR6 can be + manipulated. Keith Owens . */ + +void tulip_outl_CSR6 (struct tulip_private *tp, u32 newcsr6) +{ + long ioaddr = tp->base_addr; + const int strict_bits = 0x0060e202; + int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; + + /* common path */ + if (tp->chip_id != X3201_3) { + outl (newcsr6, ioaddr + CSR6); + return; + } + + newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ + /* read 0 on the Xircom cards */ + newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ + currcsr6 = inl (ioaddr + CSR6); + if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || + ((currcsr6 & ~0x2002) == 0)) + goto out_write; + + /* make sure the transmitter and receiver are stopped first */ + currcsr6 &= ~0x2002; + while (1) { + csr5 = inl (ioaddr + CSR5); + if (csr5 == 0xffffffff) + break; /* cannot read csr5, card removed? */ + csr5_22_20 = csr5 & 0x700000; + csr5_19_17 = csr5 & 0x0e0000; + if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && + (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) + break; /* both are stopped or suspended */ + if (!--attempts) { + printk (KERN_INFO "tulip.c: tulip_outl_CSR6 too many attempts," + "csr5=0x%08x\n", csr5); + goto out_write; + } + outl (currcsr6, ioaddr + CSR6); + udelay (1); + } + +out_write: + /* now it is safe to change csr6 */ + outl (newcsr6, ioaddr + CSR6); +} + + +static void tulip_up(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 3*HZ; + int i; + + /* Wake the chip from sleep/snooze mode. */ + if (tp->flags & HAS_ACPI) + pci_write_config_dword(tp->pdev, 0x40, 0); + + /* On some chip revs we must set the MII/SYM port before the reset!? */ + if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) + tulip_outl_CSR6 (tp, 0x00040000); + + /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ + outl(0x00000001, ioaddr + CSR0); + + /* Deassert reset. + Wait the specified 50 PCI cycles after a reset by initializing + Tx and Rx queues and the address filter list. */ + outl(tp->csr0, ioaddr + CSR0); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq); + + if (tp->flags & MC_HASH_ONLY) { + u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); + u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); + if (tp->chip_id == AX88140) { + outl(0, ioaddr + CSR13); + outl(addr_low, ioaddr + CSR14); + outl(1, ioaddr + CSR13); + outl(addr_high, ioaddr + CSR14); + } else if (tp->chip_id == COMET) { + outl(addr_low, ioaddr + 0xA4); + outl(addr_high, ioaddr + 0xA8); + outl(0, ioaddr + 0xAC); + outl(0, ioaddr + 0xB0); + } + } else { + /* This is set_rx_mode(), but without starting the transmitter. */ + u16 *eaddrs = (u16 *)dev->dev_addr; + u16 *setup_frm = &tp->setup_frame[15*6]; + + /* 21140 bug: you must add the broadcast address. */ + memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame)); + /* Fill the final entry of the table with our physical address. */ + *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; + /* Put the setup frame on the Tx list. */ + tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); + tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame); + tp->tx_ring[0].status = cpu_to_le32(DescOwned); + + tp->cur_tx++; + } + + outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3); + outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4); + + tp->saved_if_port = dev->if_port; + if (dev->if_port == 0) + dev->if_port = tp->default_port; + + /* Allow selecting a default media. */ + i = 0; + if (tp->mtable == NULL) + goto media_picked; + if (dev->if_port) { + int looking_for = tulip_media_cap[dev->if_port] & MediaIsMII ? 11 : + (dev->if_port == 12 ? 0 : dev->if_port); + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printk(KERN_INFO "%s: Using user-specified media %s.\n", + dev->name, medianame[dev->if_port]); + goto media_picked; + } + } + if ((tp->mtable->defaultmedia & 0x0800) == 0) { + int looking_for = tp->mtable->defaultmedia & 15; + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == looking_for) { + printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", + dev->name, medianame[looking_for]); + goto media_picked; + } + } + /* Start sensing first non-full-duplex media. */ + for (i = tp->mtable->leafcount - 1; + (tulip_media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) + ; +media_picked: + + tp->csr6 = 0; + tp->cur_index = i; + tp->nwayset = 0; + if (dev->if_port == 0 && tp->chip_id == DC21041) { + tp->nway = 1; + } + if (dev->if_port == 0 && tp->chip_id == DC21142) { + if (tp->mii_cnt) { + tulip_select_media(dev, 1); + if (tulip_debug > 1) + printk(KERN_INFO "%s: Using MII transceiver %d, status " + "%4.4x.\n", + dev->name, tp->phys[0], tulip_mdio_read(dev, tp->phys[0], 1)); + tulip_outl_CSR6(tp, 0x82020000); + tp->csr6 = 0x820E0000; + dev->if_port = 11; + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + } else + t21142_start_nway(dev); + } else if (tp->chip_id == PNIC2) { + t21142_start_nway(dev); + } else if (tp->chip_id == LC82C168 && ! tp->medialock) { + if (tp->mii_cnt) { + dev->if_port = 11; + tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0001, ioaddr + CSR15); + } else if (inl(ioaddr + CSR5) & TPLnkPass) + pnic_do_nway(dev); + else { + /* Start with 10mbps to do autonegotiation. */ + outl(0x32, ioaddr + CSR12); + tp->csr6 = 0x00420000; + outl(0x0001B078, ioaddr + 0xB8); + outl(0x0201B078, ioaddr + 0xB8); + next_tick = 1*HZ; + } + } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) + && ! tp->medialock) { + dev->if_port = 0; + tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) { + /* Provided by BOLO, Macronix - 12/10/1998. */ + dev->if_port = 0; + tp->csr6 = 0x01a80200; + outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); + outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); + } else if (tp->chip_id == DC21143 && + tulip_media_cap[dev->if_port] & MediaIsMII) { + /* We must reset the media CSRs when we force-select MII mode. */ + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + outl(0x0008, ioaddr + CSR15); + } else if (tp->chip_id == COMET) { + dev->if_port = 0; + tp->csr6 = 0x00040000; + } else if (tp->chip_id == AX88140) { + tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100; + } else + tulip_select_media(dev, 1); + + /* Start the chip's Tx to process setup frame. */ + tulip_outl_CSR6(tp, tp->csr6); + tulip_outl_CSR6(tp, tp->csr6 | 0x2000); + + /* Enable interrupts by setting the interrupt mask. */ + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); + outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + outl(0, ioaddr + CSR2); /* Rx poll demand */ + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", + dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), + inl(ioaddr + CSR6)); + } + /* Set the timer to switch to check for link beat and perhaps switch + to an alternate media type. */ + init_timer(&tp->timer); + tp->timer.expires = RUN_AT(next_tick); + tp->timer.data = (unsigned long)dev; + tp->timer.function = tulip_tbl[tp->chip_id].media_timer; + add_timer(&tp->timer); + + netif_device_attach(dev); +} + + +static int +tulip_open(struct net_device *dev) +{ + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } + + tulip_init_ring (dev); + + tulip_up (dev); + + return 0; +} + + +static void tulip_tx_timeout(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + + if (tulip_media_cap[dev->if_port] & MediaIsMII) { + /* Do nothing -- the media monitor should handle this. */ + if (tulip_debug > 1) + printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", + dev->name); + } else if (tp->chip_id == DC21040) { + if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) { + dev->if_port = (dev->if_port == 2 ? 0 : 2); + printk(KERN_INFO "%s: 21040 transmit timed out, switching to " + "%s.\n", + dev->name, medianame[dev->if_port]); + tulip_select_media(dev, 0); + } + goto out; + } else if (tp->chip_id == DC21041) { + int csr12 = inl(ioaddr + CSR12); + + printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, " + "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), csr12, + inl(ioaddr + CSR13), inl(ioaddr + CSR14)); + tp->mediasense = 1; + if ( ! tp->medialock) { + if (dev->if_port == 1 || dev->if_port == 2) + if (csr12 & 0x0004) { + dev->if_port = 2 - dev->if_port; + } else + dev->if_port = 0; + else + dev->if_port = 1; + tulip_select_media(dev, 0); + } + } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 + || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) { + printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " + "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), + inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); + if ( ! tp->medialock && tp->mtable) { + do + --tp->cur_index; + while (tp->cur_index >= 0 + && (tulip_media_cap[tp->mtable->mleaf[tp->cur_index].media] + & MediaIsFD)); + if (--tp->cur_index < 0) { + /* We start again, but should instead look for default. */ + tp->cur_index = tp->mtable->leafcount - 1; + } + tulip_select_media(dev, 0); + printk(KERN_WARNING "%s: transmit timed out, switching to %s " + "media.\n", dev->name, medianame[dev->if_port]); + } + } else { + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " + "%8.8x, resetting...\n", + dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); + dev->if_port = 0; + } + +#if defined(way_too_many_messages) + if (tulip_debug > 3) { + int i; + for (i = 0; i < RX_RING_SIZE; i++) { + u8 *buf = (u8 *)(tp->rx_ring[i].buffer1); + int j; + printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x " + "%2.2x %2.2x %2.2x.\n", + i, (unsigned int)tp->rx_ring[i].status, + (unsigned int)tp->rx_ring[i].length, + (unsigned int)tp->rx_ring[i].buffer1, + (unsigned int)tp->rx_ring[i].buffer2, + buf[0], buf[1], buf[2]); + for (j = 0; buf[j] != 0xee && j < 1600; j++) + if (j < 100) printk(" %2.2x", buf[j]); + printk(" j=%d.\n", j); + } + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); + printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); + printk("\n"); + } +#endif + + /* Stop and restart the chip's Tx processes . */ + tulip_outl_CSR6(tp, tp->csr6 | 0x0002); + tulip_outl_CSR6(tp, tp->csr6 | 0x2002); + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + + tp->stats.tx_errors++; + +out: + dev->trans_start = jiffies; + netif_start_queue (dev); + spin_unlock_irqrestore (&tp->lock, flags); +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void tulip_init_ring(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int i; + + tp->tx_full = 0; + tp->cur_rx = tp->cur_tx = 0; + tp->dirty_rx = tp->dirty_tx = 0; + tp->susp_rx = 0; + tp->ttimer = 0; + tp->nir = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + tp->rx_ring[i].status = 0x00000000; + tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); + tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]); + tp->rx_skbuff[i] = NULL; + } + /* Mark the last entry as wrapping the ring. */ + tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP); + tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]); + + for (i = 0; i < RX_RING_SIZE; i++) { + /* Note the receive buffer must be longword aligned. + dev_alloc_skb() provides 16 byte alignment. But do *not* + use skb_reserve() to align the IP header! */ + struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); + tp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */ + tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail); + } + tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + /* The Tx buffer descriptor is filled in as needed, but we + do need to clear the ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + tp->tx_skbuff[i] = 0; + tp->tx_ring[i].status = 0x00000000; + tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]); + } + tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]); +} + +static int +tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + int entry; + u32 flag; + unsigned long cpuflags; + + /* Caution: the write order is important here, set the field + with the ownership bits last. */ + + spin_lock_irqsave(&tp->lock, cpuflags); + + /* Calculate the next Tx descriptor entry. */ + entry = tp->cur_tx % TX_RING_SIZE; + + tp->tx_skbuff[entry] = skb; + tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data); + + if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ + flag = 0x60000000; /* No interrupt */ + } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { + flag = 0xe0000000; /* Tx-done intr. */ + } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { + flag = 0x60000000; /* No Tx-done intr. */ + } else { /* Leave room for set_rx_mode() to fill entries. */ + tp->tx_full = 1; + flag = 0xe0000000; /* Tx-done intr. */ + netif_stop_queue(dev); + } + if (entry == TX_RING_SIZE-1) + flag = 0xe0000000 | DESC_RING_WRAP; + + tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag); + tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + tp->cur_tx++; + + /* Trigger an immediate transmit demand. */ + outl(0, dev->base_addr + CSR1); + + spin_unlock_irqrestore(&tp->lock, cpuflags); + + dev->trans_start = jiffies; + + return 0; +} + +static void tulip_down (struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *) dev->priv; + unsigned long flags; + + netif_device_detach (dev); + + del_timer (&tp->timer); + + spin_lock_irqsave (&tp->lock, flags); + + /* Disable interrupts by clearing the interrupt mask. */ + outl (0x00000000, ioaddr + CSR7); + + /* Stop the Tx and Rx processes. */ + tulip_outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002); + + /* 21040 -- Leave the card in 10baseT state. */ + if (tp->chip_id == DC21040) + outl (0x00000004, ioaddr + CSR13); + + if (inl (ioaddr + CSR6) != 0xffffffff) + tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff; + + spin_unlock_irqrestore (&tp->lock, flags); + + dev->if_port = tp->saved_if_port; + + /* Leave the driver in snooze, not sleep, mode. */ + if (tp->flags & HAS_ACPI) + pci_write_config_dword (tp->pdev, 0x40, 0x40000000); +} + + +static int tulip_close (struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *) dev->priv; + int i; + + tulip_down (dev); + + if (tulip_debug > 1) + printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inl (ioaddr + CSR5)); + + free_irq (dev->irq, dev); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = tp->rx_skbuff[i]; + tp->rx_skbuff[i] = 0; + tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ + tp->rx_ring[i].length = 0; + tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ + if (skb) { + dev_kfree_skb (skb); + } + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (tp->tx_skbuff[i]) + dev_kfree_skb (tp->tx_skbuff[i]); + tp->tx_skbuff[i] = 0; + } + + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct enet_statistics *tulip_get_stats(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + + if (netif_running(dev)) { + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + + tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + + spin_unlock_irqrestore(&tp->lock, flags); + } + + return &tp->stats; +} + + +/* Provide ioctl() calls to examine the MII xcvr state. */ +static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + u16 *data = (u16 *)&rq->ifr_data; + int phy = tp->phys[0] & 0x1f; + long flags; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + if (tp->mii_cnt) + data[0] = phy; + else if (tp->flags & HAS_NWAY143) + data[0] = 32; + else if (tp->chip_id == COMET) + data[0] = 1; + else + return -ENODEV; + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { + int csr12 = inl(ioaddr + CSR12); + int csr14 = inl(ioaddr + CSR14); + switch (data[1]) { + case 0: { + data[3] = (csr14<<5) & 0x1000; + break; } + case 1: + data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) + + (csr12&0x06 ? 0x04 : 0); + break; + case 4: { + data[3] = ((csr14>>9)&0x07C0) + + ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1; + break; + } + case 5: data[3] = csr12 >> 16; break; + default: data[3] = 0; break; + } + } else { + spin_lock_irqsave (&tp->lock, flags); + data[3] = tulip_mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + spin_unlock_irqrestore (&tp->lock, flags); + } + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { + if (data[1] == 5) + tp->to_advertise = data[2]; + } else { + spin_lock_irqsave (&tp->lock, flags); + tulip_mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + spin_unlock_irqrestore(&tp->lock, flags); + } + return 0; + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} + + +/* Set or clear the multicast filter for this adaptor. + Note that we only use exclusion around actually queueing the + new frame, not around filling tp->setup_frame. This is non-deterministic + when re-entered but still correct. */ + +/* The little-endian AUTODIN32 ethernet CRC calculation. + N.B. Do not use for bulk data, use a table-based routine instead. + This is common code and should be moved to net/core/crc.c */ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline u32 ether_crc_le(int length, unsigned char *data) +{ + u32 crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc(int length, unsigned char *data) +{ + int crc = -1; + + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + struct tulip_private *tp = (struct tulip_private *)dev->priv; + long ioaddr = dev->base_addr; + int csr6 = inl(ioaddr + CSR6) & ~0x00D5; + + tp->csr6 &= ~0x00D5; + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + tp->csr6 |= 0x00C0; + csr6 |= 0x00C0; + /* Unconditionally log net taps. */ + printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); + } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter well -- accept all multicasts. */ + tp->csr6 |= 0x0080; + csr6 |= 0x0080; + } else if (tp->flags & MC_HASH_ONLY) { + /* Some work-alikes have only a 64-entry hash filter table. */ + /* Should verify correctness on big-endian/__powerpc__ */ + struct dev_mc_list *mclist; + int i; + u32 mc_filter[2]; /* Multicast hash filter */ + if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ + tp->csr6 |= 0x0080; + csr6 |= 0x0080; + } else { + mc_filter[1] = mc_filter[0] = 0; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); + if (tp->chip_id == AX88140) { + outl(2, ioaddr + CSR13); + outl(mc_filter[0], ioaddr + CSR14); + outl(3, ioaddr + CSR13); + outl(mc_filter[1], ioaddr + CSR14); + } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ + outl(mc_filter[0], ioaddr + 0xAC); + outl(mc_filter[1], ioaddr + 0xB0); + } + } + } else { + u16 *eaddrs, *setup_frm = tp->setup_frame; + struct dev_mc_list *mclist; + u32 tx_flags = 0x08000000 | 192; + int i; + unsigned long flags; + + /* Note that only the low-address shortword of setup_frame is valid! + The values are doubled for big-endian architectures. */ + if (dev->mc_count > 14) { /* Must use a multicast hash table. */ + u16 hash_table[32]; + tx_flags = 0x08400000 | 192; /* Use hash filter. */ + memset(hash_table, 0, sizeof(hash_table)); + set_bit(255, hash_table); /* Broadcast entry */ + /* This should work on big-endian machines as well. */ + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, + hash_table); + for (i = 0; i < 32; i++) + *setup_frm++ = *setup_frm++ = hash_table[i]; + setup_frm = &tp->setup_frame[13*6]; + } else { + /* We have <= 14 addresses so we can use the wonderful + 16 address perfect filtering of the Tulip. */ + for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + i++, mclist = mclist->next) { + eaddrs = (u16 *)mclist->dmi_addr; + *setup_frm++ = *setup_frm++ = *eaddrs++; + *setup_frm++ = *setup_frm++ = *eaddrs++; + *setup_frm++ = *setup_frm++ = *eaddrs++; + } + /* Fill the unused entries with the broadcast address. */ + memset(setup_frm, 0xff, (15-i)*12); + setup_frm = &tp->setup_frame[15*6]; + } + + /* Fill the final entry with our physical address. */ + eaddrs = (u16 *)dev->dev_addr; + *setup_frm++ = *setup_frm++ = eaddrs[0]; + *setup_frm++ = *setup_frm++ = eaddrs[1]; + *setup_frm++ = *setup_frm++ = eaddrs[2]; + + spin_lock_irqsave(&tp->lock, flags); + + if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { + /* Same setup recently queued, we need not add it. */ + } else { + unsigned int entry; + + /* Now add this frame to the Tx list. */ + + entry = tp->cur_tx++ % TX_RING_SIZE; + + if (entry != 0) { + /* Avoid a chip errata by prefixing a dummy entry. */ + tp->tx_skbuff[entry] = 0; + tp->tx_ring[entry].length = + (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; + tp->tx_ring[entry].buffer1 = 0; + tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + entry = tp->cur_tx++ % TX_RING_SIZE; + } + + tp->tx_skbuff[entry] = 0; + /* Put the setup frame on the Tx list. */ + if (entry == TX_RING_SIZE-1) + tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ + tp->tx_ring[entry].length = cpu_to_le32(tx_flags); + tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame); + tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { + netif_stop_queue(dev); + tp->tx_full = 1; + } + + /* Trigger an immediate transmit demand. */ + outl(0, ioaddr + CSR1); + + } + + spin_unlock_irqrestore(&tp->lock, flags); + } + tulip_outl_CSR6(tp, csr6 | 0x0000); +} + + +static int __devinit tulip_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int did_version = 0; /* Already printed version info. */ + struct tulip_private *tp; + /* See note below on the multiport cards. */ + static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; + static int last_irq = 0; + static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */ + u8 chip_rev; + int i, irq; + unsigned short sum; + u8 ee_data[EEPROM_SIZE]; + struct net_device *dev; + long ioaddr; + static int board_idx = -1; + int chip_idx = ent->driver_data; + + board_idx++; + + if (tulip_debug > 0 && did_version++ == 0) + printk (KERN_INFO "%s", version); + + if( pdev->subsystem_vendor == 0x1376 ){ + printk (KERN_ERR PFX "skipping LMC card.\n"); + return -ENODEV; + } + + ioaddr = pci_resource_start (pdev, 0); + irq = pdev->irq; + + /* init_etherdev ensures qword aligned structures */ + dev = init_etherdev (NULL, sizeof (*tp)); + if (!dev) { + printk (KERN_ERR PFX "ether device alloc failed, aborting\n"); + return -ENOMEM; + } + + /* We do a request_region() only to register /proc/ioports info. */ + /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ + if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) { + printk (KERN_ERR PFX "I/O ports (0x%x@0x%lx) unavailable, " + "aborting\n", tulip_tbl[chip_idx].io_size, ioaddr); + goto err_out_free_netdev; + } + + if (pci_enable_device(pdev)) { + printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, " + "bus %d, devfn %d), aborting\n", + pdev->vendor, pdev->device, + pdev->bus->number, pdev->devfn); + goto err_out_free_netdev; + } + + pci_set_master(pdev); + + pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); + + /* + * initialize priviate data structure 'tp' + * it is zeroed and aligned in init_etherdev + */ + tp = dev->priv; + + tp->chip_id = chip_idx; + tp->flags = tulip_tbl[chip_idx].flags; + tp->pdev = pdev; + tp->base_addr = ioaddr; + tp->revision = chip_rev; + spin_lock_init(&tp->lock); + +#ifdef TULIP_FULL_DUPLEX + tp->full_duplex = 1; + tp->full_duplex_lock = 1; +#endif +#ifdef TULIP_DEFAULT_MEDIA + tp->default_port = TULIP_DEFAULT_MEDIA; +#endif +#ifdef TULIP_NO_MEDIA_SWITCH + tp->medialock = 1; +#endif + + printk(KERN_INFO "%s: %s rev %d at %#3lx,", + dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); + + /* Stop the chip's Tx and Rx processes. */ + tulip_outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002); + /* Clear the missed-packet counter. */ + (volatile int)inl(ioaddr + CSR8); + + if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { + printk(" 21040 compatible mode,"); + chip_idx = DC21040; + } + + /* The station address ROM is read byte serially. The register must + be polled, waiting for the value to be read bit serially from the + EEPROM. + */ + sum = 0; + if (chip_idx == DC21040) { + outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ + for (i = 0; i < 6; i++) { + int value, boguscnt = 100000; + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + dev->dev_addr[i] = value; + sum += value & 0xff; + } + } else if (chip_idx == LC82C168) { + for (i = 0; i < 3; i++) { + int value, boguscnt = 100000; + outl(0x600 | i, ioaddr + 0x98); + do + value = inl(ioaddr + CSR9); + while (value < 0 && --boguscnt > 0); + put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); + sum += value & 0xffff; + } + } else if (chip_idx == COMET) { + /* No need to read the EEPROM. */ + put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); + put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); + for (i = 0; i < 6; i ++) + sum += dev->dev_addr[i]; + } else { + /* A serial EEPROM interface, we read now and sort it out later. */ + int sa_offset = 0; + int ee_addr_size = tulip_read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; + + for (i = 0; i < sizeof(ee_data)/2; i++) + ((u16 *)ee_data)[i] = + le16_to_cpu(tulip_read_eeprom(ioaddr, i, ee_addr_size)); + + /* DEC now has a specification (see Notes) but early board makers + just put the address in the first EEPROM locations. */ + /* This does memcmp(eedata, eedata+16, 8) */ + for (i = 0; i < 8; i ++) + if (ee_data[i] != ee_data[16+i]) + sa_offset = 20; + if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { + sa_offset = 2; /* Grrr, damn Matrox boards. */ + multiport_cnt = 4; + } + for (i = 0; i < 6; i ++) { + dev->dev_addr[i] = ee_data[i + sa_offset]; + sum += ee_data[i + sa_offset]; + } + } + /* Lite-On boards have the address byte-swapped. */ + if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) + && dev->dev_addr[1] == 0x00) + for (i = 0; i < 6; i+=2) { + char tmp = dev->dev_addr[i]; + dev->dev_addr[i] = dev->dev_addr[i+1]; + dev->dev_addr[i+1] = tmp; + } + /* On the Zynx 315 Etherarray and other multiport boards only the + first Tulip has an EEPROM. + The addresses of the subsequent ports are derived from the first. + Many PCI BIOSes also incorrectly report the IRQ line, so we correct + that here as well. */ + if (sum == 0 || sum == 6*0xff) { + printk(" EEPROM not present,"); + for (i = 0; i < 5; i++) + dev->dev_addr[i] = last_phys_addr[i]; + dev->dev_addr[i] = last_phys_addr[i] + 1; +#if defined(__i386__) /* Patch up x86 BIOS bug. */ + if (last_irq) + irq = last_irq; +#endif + } + + for (i = 0; i < 6; i++) + printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]); + printk(", IRQ %d.\n", irq); + last_irq = irq; + + pdev->driver_data = dev; + dev->base_addr = ioaddr; + dev->irq = irq; + tp->csr0 = csr0; + + /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. + And the ASIX must have a burst limit or horrible things happen. */ + if (chip_idx == DC21143 && chip_rev == 65) + tp->csr0 &= ~0x01000000; + else if (chip_idx == AX88140) + tp->csr0 |= 0x2000; + + /* The lower four bits are the media type. */ + if (board_idx >= 0 && board_idx < MAX_UNITS) { + tp->default_port = options[board_idx] & 15; + if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0) + tp->full_duplex = 1; + if (mtu[board_idx] > 0) + dev->mtu = mtu[board_idx]; + } + if (dev->mem_start) + tp->default_port = dev->mem_start; + if (tp->default_port) { + tp->medialock = 1; + if (tulip_media_cap[tp->default_port] & MediaAlwaysFD) + tp->full_duplex = 1; + } + if (tp->full_duplex) + tp->full_duplex_lock = 1; + + if (tulip_media_cap[tp->default_port] & MediaIsMII) { + u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; + tp->to_advertise = media2advert[tp->default_port - 9]; + } else if (tp->flags & HAS_8023X) + tp->to_advertise = 0x05e1; + else + tp->to_advertise = 0x01e1; + + /* This is logically part of probe1(), but too complex to write inline. */ + if (tp->flags & HAS_MEDIA_TABLE) { + memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); + tulip_parse_eeprom(dev); + } + + if ((tp->flags & ALWAYS_CHECK_MII) || + (tp->mtable && tp->mtable->has_mii) || + ( ! tp->mtable && (tp->flags & HAS_MII))) { + int phy, phy_idx; + if (tp->mtable && tp->mtable->has_mii) { + for (i = 0; i < tp->mtable->leafcount; i++) + if (tp->mtable->mleaf[i].media == 11) { + tp->cur_index = i; + tp->saved_if_port = dev->if_port; + tulip_select_media(dev, 1); + dev->if_port = tp->saved_if_port; + break; + } + } + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, + but takes much time. */ + for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); + phy++) { + int mii_status = tulip_mdio_read(dev, phy, 1); + if ((mii_status & 0x8301) == 0x8001 || + ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { + int mii_reg0 = tulip_mdio_read(dev, phy, 0); + int mii_advert = tulip_mdio_read(dev, phy, 4); + int reg4 = ((mii_status>>6) & tp->to_advertise) | 1; + tp->phys[phy_idx] = phy; + tp->advertising[phy_idx++] = reg4; + printk(KERN_INFO "%s: MII transceiver #%d " + "config %4.4x status %4.4x advertising %4.4x.\n", + dev->name, phy, mii_reg0, mii_status, mii_advert); + /* Fixup for DLink with miswired PHY. */ + if (mii_advert != reg4) { + printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d," + " previously advertising %4.4x.\n", + dev->name, reg4, phy, mii_advert); + printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise" + " is %4.4x).\n", + dev->name, reg4, tp->to_advertise); + tulip_mdio_write(dev, phy, 4, reg4); + } + /* Enable autonegotiation: some boards default to off. */ + tulip_mdio_write(dev, phy, 0, mii_reg0 | + (tp->full_duplex ? 0x1100 : 0x1000) | + (tulip_media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); + } + } + tp->mii_cnt = phy_idx; + if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { + printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", + dev->name); + tp->phys[0] = 1; + } + } + + /* The Tulip-specific entries in the device structure. */ + dev->open = tulip_open; + dev->hard_start_xmit = tulip_start_xmit; + dev->tx_timeout = tulip_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = tulip_close; + dev->get_stats = tulip_get_stats; + dev->do_ioctl = private_ioctl; + dev->set_multicast_list = set_rx_mode; + + if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041) + tp->link_change = t21142_lnk_change; + else if (tp->flags & HAS_PNICNWAY) + tp->link_change = pnic_lnk_change; + + /* Reset the xcvr interface and turn on heartbeat. */ + switch (chip_idx) { + case DC21041: + tp->to_advertise = 0x0061; + outl(0x00000000, ioaddr + CSR13); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ + tulip_outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200); + outl(0x0000EF05, ioaddr + CSR13); + break; + case DC21040: + outl(0x00000000, ioaddr + CSR13); + outl(0x00000004, ioaddr + CSR13); + break; + case DC21140: + default: + if (tp->mtable) + outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); + break; + case DC21142: + case PNIC2: + if (tp->mii_cnt || tulip_media_cap[dev->if_port] & MediaIsMII) { + tulip_outl_CSR6(tp, 0x82020000); + outl(0x0000, ioaddr + CSR13); + outl(0x0000, ioaddr + CSR14); + tulip_outl_CSR6(tp, 0x820E0000); + } else + t21142_start_nway(dev); + break; + case LC82C168: + if ( ! tp->mii_cnt) { + tp->nway = 1; + tp->nwayset = 0; + tulip_outl_CSR6(tp, 0x00420000); + outl(0x30, ioaddr + CSR12); + tulip_outl_CSR6(tp, 0x0001F078); + tulip_outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */ + } + break; + case MX98713: case COMPEX9881: + tulip_outl_CSR6(tp, 0x00000000); + outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ + outl(0x00000001, ioaddr + CSR13); + break; + case MX98715: case MX98725: + tulip_outl_CSR6(tp, 0x01a80000); + outl(0xFFFFFFFF, ioaddr + CSR14); + outl(0x00001000, ioaddr + CSR12); + break; + case COMET: + /* No initialization necessary. */ + break; + } + + /* put the chip in snooze mode until opened */ + if (tulip_tbl[chip_idx].flags & HAS_ACPI) + pci_write_config_dword(pdev, 0x40, 0x40000000); + + return 0; + +err_out_free_netdev: + unregister_netdev (dev); + kfree (dev); + return -ENODEV; +} + + +static void tulip_suspend (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (dev && netif_device_present (dev)) + tulip_down (dev); +} + + +static void tulip_resume (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (dev && !netif_device_present (dev)) + tulip_up (dev); +} + + +static void __devexit tulip_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + if (dev) { + struct tulip_private *tp = (struct tulip_private *)dev->priv; + unregister_netdev(dev); + release_region(dev->base_addr, + tulip_tbl[tp->chip_id].io_size); + kfree(dev); + } +} + + +static struct pci_driver tulip_driver = { + name: TULIP_MODULE_NAME, + id_table: tulip_pci_tbl, + probe: tulip_init_one, + remove: tulip_remove_one, + suspend: tulip_suspend, + resume: tulip_resume, +}; + + +static int __init tulip_init (void) +{ + /* copy module parms into globals */ + tulip_rx_copybreak = rx_copybreak; + tulip_max_interrupt_work = max_interrupt_work; + + /* probe for and init boards */ + return pci_module_init (&tulip_driver); +} + + +static void __exit tulip_cleanup (void) +{ + pci_unregister_driver (&tulip_driver); +} + + +module_init(tulip_init); +module_exit(tulip_cleanup); diff -u --recursive --new-file v2.3.47/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.3.47/linux/drivers/net/tulip.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/tulip.c Wed Dec 31 16:00:00 1969 @@ -1,3159 +0,0 @@ -/* tulip.c: A DEC 21040-family ethernet driver for Linux. */ -/* - Copyright 2000 The Linux Kernel Team - Written/copyright 1994-1999 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. - - This driver is for the Digital "Tulip" Ethernet adapter interface. - It should work with most DEC 21*4*-based chips/ethercards, as well as - with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX. - - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - - Additional information available at - http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html - - For this specific driver variant please use linux-kernel for - bug reports. - - - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the DECchip "Tulip", Digital's -single-chip ethernet controllers for PCI. Supported members of the family -are the 21040, 21041, 21140, 21140A, 21142, and 21143. Similar work-alike -chips from Lite-On, Macronics, ASIX, Compex and other listed below are also -supported. - -These chips are used on at least 140 unique PCI board designs. The great -number of chips and board designs supported is the reason for the -driver size and complexity. Almost of the increasing complexity is in the -board configuration and media selection code. There is very little -increasing in the operational critical path length. - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS preferably should assign the -PCI INTA signal to an otherwise unused system IRQ line. - -Some boards have EEPROMs tables with default media entry. The factory default -is usually "autoselect". This should only be overridden when using -transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!) -for forcing full-duplex when used with old link partners that do not do -autonegotiation. - -III. Driver operation - -IIIa. Ring buffers - -The Tulip can use either ring buffers or lists of Tx and Rx descriptors. -This driver uses statically allocated rings of Rx and Tx descriptors, set at -compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs -for the Rx ring buffers at open() time and passes the skb->data field to the -Tulip as receive data buffers. When an incoming frame is less than -RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is -copied to the new skbuff. When the incoming frame is larger, the skbuff is -passed directly up the protocol stack and replaced by a newly allocated -skbuff. - -The RX_COPYBREAK value is chosen to trade-off the memory wasted by -using a full-sized skbuff for small frames vs. the copying costs of larger -frames. For small frames the copying cost is negligible (esp. considering -that we are pre-loading the cache with immediately useful header -information). For large frames the copying cost is non-trivial, and the -larger copy might flush the cache of useful data. A subtle aspect of this -choice is that the Tulip only receives into longword aligned buffers, thus -the IP header at offset 14 isn't longword aligned for further processing. -Copied frames are put into the new skbuff at an offset of "+2", thus copying -has the beneficial effect of aligning the IP header and preloading the -cache. - -IIIC. Synchronization -The driver runs as two independent, single-threaded flows of control. One -is the send-packet routine, which enforces single-threaded use by the -dev->tbusy flag. The other thread is the interrupt handler, which is single -threaded by the hardware and other software. - -The send packet thread has partial control over the Tx ring and 'dev->tbusy' -flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next -queue slot is empty, it clears the tbusy flag when finished otherwise it sets -the 'tp->tx_full' flag. - -The interrupt handler has exclusive control over the Rx ring and records stats -from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so -we can't avoid the interrupt overhead by having the Tx routine reap the Tx -stats.) After reaping the stats, it marks the queue entry as empty by setting -the 'base' to zero. Iff the 'tp->tx_full' flag is set, it clears both the -tx_full and tbusy flags. - -IV. Notes - -Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board. -Greg LaPolla at Linksys provided PNIC and other Linksys boards. -Znyx provided a four-port card for testing. - -IVb. References - -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html -http://www.digital.com (search for current 21*4* datasheets and "21X4 SROM") -http://www.national.com/pf/DP/DP83840A.html -http://www.asix.com.tw/pmac.htm -http://www.admtek.com.tw/ - -IVc. Errata - -The old DEC databooks were light on details. -The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last -register of the set CSR12-15 written. Hmmm, now how is that possible? - -The DEC SROM format is very badly designed not precisely defined, leading to -part of the media selection junkheap below. Some boards do not have EEPROM -media tables and need to be patched up. Worse, other boards use the DEC -design kit media table when it isn't correct for their board. - -We cannot use MII interrupts because there is no defined GPIO pin to attach -them. The MII transceiver status is polled using an kernel timer. - -*/ - -static const char version[] = "Linux Tulip driver version 0.9.2 (Feb 15, 2000)\n"; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Processor type for cache alignment. */ -#include -#include -#include -#include - - -/* A few user-configurable values. */ - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 25; - -#define MAX_UNITS 8 -/* Used to pass the full-duplex flag, etc. */ -static int full_duplex[MAX_UNITS] = {0, }; -static int options[MAX_UNITS] = {0, }; -static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */ - -/* The possible media types that can be set in options[] are: */ -static const char * const medianame[] = { - "10baseT", "10base2", "AUI", "100baseTx", - "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", - "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", - "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", -}; - -/* Set if the PCI BIOS detects the chips on a multiport board backwards. */ -#ifdef REVERSE_PROBE_ORDER -static int reverse_probe = 1; -#else -static int reverse_probe = 0; -#endif - -/* Keep the ring sizes a power of two for efficiency. - Making the Tx ring too large decreases the effectiveness of channel - bonding and packet priority. - There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 16 -#define RX_RING_SIZE 32 - -/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ -#ifdef __alpha__ -static int rx_copybreak = 1518; -#else -static int rx_copybreak = 100; -#endif - -/* - Set the bus performance register. - Typical: Set 16 longword cache alignment, no burst limit. - Cache alignment bits 15:14 Burst length 13:8 - 0000 No alignment 0x00000000 unlimited 0800 8 longwords - 4000 8 longwords 0100 1 longword 1000 16 longwords - 8000 16 longwords 0200 2 longwords 2000 32 longwords - C000 32 longwords 0400 4 longwords - Warning: many older 486 systems are broken and require setting 0x00A04800 - 8 longword cache alignment, 8 longword burst. - ToDo: Non-Intel setting could be better. -*/ - -#if defined(__alpha__) -static int csr0 = 0x01A00000 | 0xE000; -#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__) -static int csr0 = 0x01A00000 | 0x8000; -#else -#warning Processor architecture undefined! -static int csr0 = 0x00A00000 | 0x4800; -#endif - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (4*HZ) -#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -/* This is a mysterious value that can be written to CSR11 in the 21040 (only) - to support a pre-NWay full-duplex signaling mechanism using short frames. - No one knows what it should be, but if left at its default value some - 10base2(!) packets trigger a full-duplex-request interrupt. */ -#define FULL_DUPLEX_MAGIC 0x6969 - - -/* Kernel compatibility defines, some common to David Hind's PCMCIA package. - This is only in the support-all-kernels source code. */ - -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver"); -MODULE_PARM(debug, "i"); -MODULE_PARM(max_interrupt_work, "i"); -MODULE_PARM(reverse_probe, "i"); -MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(csr0, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); - -#define TULIP_MODULE_NAME "tulip" -#define PFX TULIP_MODULE_NAME ": " - -#define RUN_AT(x) (jiffies + (x)) - -/* Condensed operations for readability. */ -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - -#define tulip_debug debug -#ifdef TULIP_DEBUG -static int tulip_debug = TULIP_DEBUG; -#else -static int tulip_debug = 1; -#endif - - - -/* This table use during operation for capabilities and media timer. */ - -static void tulip_timer(unsigned long data); -static void t21142_timer(unsigned long data); -static void mxic_timer(unsigned long data); -static void pnic_timer(unsigned long data); -static void comet_timer(unsigned long data); - -enum tbl_flag { - HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8, - HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */ - HAS_PNICNWAY=0x80, HAS_NWAY143=0x40, /* Uses internal NWay xcvr. */ - HAS_8023X=0x100, -}; -static struct tulip_chip_table { - char *chip_name; - int io_size; - int valid_intrs; /* CSR7 interrupt enable settings */ - int flags; - void (*media_timer)(unsigned long data); -} tulip_tbl[] = { - { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer }, - { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer }, - { "Digital DS21140 Tulip", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, - { "Digital DS21143 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, - t21142_timer }, - { "Lite-On 82c168 PNIC", 256, 0x0001ebef, - HAS_MII | HAS_PNICNWAY, pnic_timer }, - { "Macronix 98713 PMAC", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, - { "Macronix 98715 PMAC", 256, 0x0001ebef, - HAS_MEDIA_TABLE, mxic_timer }, - { "Macronix 98725 PMAC", 256, 0x0001ebef, - HAS_MEDIA_TABLE, mxic_timer }, - { "ASIX AX88140", 128, 0x0001fbff, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, - { "Lite-On PNIC-II", 256, 0x0801fbff, - HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer }, - { "ADMtek Comet", 256, 0x0001abef, - MC_HASH_ONLY, comet_timer }, - { "Compex 9881 PMAC", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, - { "Intel DS21145 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143, - t21142_timer }, - { "Xircom tulip work-alike", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, - t21142_timer }, - {0}, -}; -/* This matches the table above. Note 21142 == 21143. */ -enum chips { - DC21040=0, - DC21041=1, - DC21140=2, - DC21142=3, DC21143=3, - LC82C168, - MX98713, - MX98715, - MX98725, - AX88140, - PNIC2, - COMET, - COMPEX9881, - I21145, - X3201_3, -}; - - -static struct pci_device_id tulip_pci_tbl[] __devinitdata = { - { 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 }, - { 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 }, - { 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 }, - { 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 }, - { 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 }, - { 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 }, - { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 }, - { 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 }, - { 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 }, - { 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 }, - { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, - { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, - { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, - { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, - {0}, -}; -MODULE_DEVICE_TABLE(pci,tulip_pci_tbl); - - -/* A full-duplex map for media types. */ -enum MediaIs { - MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8, - MediaIs100=16}; -static const char media_cap[] = -{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 }; -static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0}; -/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/ -static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, }; -static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, }; -static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; - -static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, }; -static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, }; -static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, }; - -/* Offsets to the Command and Status Registers, "CSRs". All accesses - must be longword instructions and quadword aligned. */ -enum tulip_offsets { - CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, - CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, - CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 }; - -/* The bits in the CSR5 status registers, mostly interrupt sources. */ -enum status_bits { - TimerInt=0x800, SytemError=0x2000, TPLnkFail=0x1000, TPLnkPass=0x10, - NormalIntr=0x10000, AbnormalIntr=0x8000, - RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, - TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01, -}; - -/* The Tulip Rx and Tx buffer descriptors. */ -struct tulip_rx_desc { - s32 status; - s32 length; - u32 buffer1, buffer2; -}; - -struct tulip_tx_desc { - s32 status; - s32 length; - u32 buffer1, buffer2; /* We use only buffer 1. */ -}; - -enum desc_status_bits { - DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300, -}; - -/* Ring-wrap flag in length field, use for last ring entry. - 0x01000000 means chain on buffer2 address, - 0x02000000 means use the ring start address in CSR2/3. - Note: Some work-alike chips do not function correctly in chained mode. - The ASIX chip works only in chained mode. - Thus we indicates ring mode, but always write the 'next' field for - chained mode as well. -*/ -#define DESC_RING_WRAP 0x02000000 - -#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */ - -struct medialeaf { - u8 type; - u8 media; - unsigned char *leafdata; -}; - -struct mediatable { - u16 defaultmedia; - u8 leafcount, csr12dir; /* General purpose pin directions. */ - unsigned has_mii:1, has_nonmii:1, has_reset:6; - u32 csr15dir, csr15val; /* 21143 NWay setting. */ - struct medialeaf mleaf[0]; -}; - -struct mediainfo { - struct mediainfo *next; - int info_type; - int index; - unsigned char *info; -}; - -struct tulip_private { - char devname[8]; /* Used only for kernel debugging. */ - const char *product_name; - struct net_device *next_module; - struct tulip_rx_desc rx_ring[RX_RING_SIZE]; - struct tulip_tx_desc tx_ring[TX_RING_SIZE]; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff* tx_skbuff[TX_RING_SIZE]; - /* The addresses of receive-in-place skbuffs. */ - struct sk_buff* rx_skbuff[RX_RING_SIZE]; - char *rx_buffs; /* Address of temporary Rx buffers. */ - u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */ - int chip_id; - int revision; - int flags; - struct net_device_stats stats; - struct timer_list timer; /* Media selection timer. */ - spinlock_t tx_lock; - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int full_duplex:1; /* Full-duplex operation requested. */ - unsigned int full_duplex_lock:1; - unsigned int fake_addr:1; /* Multiport board faked address. */ - unsigned int default_port:4; /* Last dev->if_port value. */ - unsigned int media2:4; /* Secondary monitored media port. */ - unsigned int medialock:1; /* Don't sense media type. */ - unsigned int mediasense:1; /* Media sensing in progress. */ - unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */ - unsigned int csr0; /* CSR0 setting. */ - unsigned int csr6; /* Current CSR6 control settings. */ - unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ - void (*link_change)(struct net_device *dev, int csr5); - u16 to_advertise; /* NWay capabilities advertised. */ - u16 lpar; /* 21143 Link partner ability. */ - u16 advertising[4]; - signed char phys[4], mii_cnt; /* MII device addresses. */ - struct mediatable *mtable; - int cur_index; /* Current media index. */ - int saved_if_port; - struct pci_dev *pdev; - int ttimer; - int susp_rx; - unsigned long nir; - unsigned long base_addr; - int pad0, pad1; /* Used for 8-byte alignment */ -}; - -static void parse_eeprom(struct net_device *dev); -static int read_eeprom(long ioaddr, int location, int addr_len); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static void select_media(struct net_device *dev, int startup); -/* Chip-specific media selection (timer functions prototyped above). */ -static void t21142_lnk_change(struct net_device *dev, int csr5); -static void t21142_start_nway(struct net_device *dev); -static void pnic_lnk_change(struct net_device *dev, int csr5); -static void pnic_do_nway(struct net_device *dev); - -static void tulip_tx_timeout(struct net_device *dev); -static void tulip_init_ring(struct net_device *dev); -static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int tulip_refill_rx(struct net_device *dev); -static int tulip_rx(struct net_device *dev); -static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); -static int tulip_open(struct net_device *dev); -static int tulip_close(struct net_device *dev); -static void tulip_up(struct net_device *dev); -static void tulip_down(struct net_device *dev); -static struct net_device_stats *tulip_get_stats(struct net_device *dev); -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void set_rx_mode(struct net_device *dev); - - -/* Serial EEPROM section. */ -/* The main routine to parse the very complicated SROM structure. - Search www.digital.com for "21X4 SROM" to get details. - This code is very complex, and will require changes to support - additional cards, so I'll be verbose about what is going on. - */ - -/* Known cards that have old-style EEPROMs. */ -static struct fixups { - char *name; - unsigned char addr0, addr1, addr2; - u16 newtable[32]; /* Max length below. */ -} eeprom_fixups[] = { - {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c, - 0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }}, - {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f, - 0x0000, 0x009E, /* 10baseT */ - 0x0004, 0x009E, /* 10baseT-FD */ - 0x0903, 0x006D, /* 100baseTx */ - 0x0905, 0x006D, /* 100baseTx-FD */ }}, - {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f, - 0x0107, 0x8021, /* 100baseFx */ - 0x0108, 0x8021, /* 100baseFx-FD */ - 0x0100, 0x009E, /* 10baseT */ - 0x0104, 0x009E, /* 10baseT-FD */ - 0x0103, 0x006D, /* 100baseTx */ - 0x0105, 0x006D, /* 100baseTx-FD */ }}, - {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513, - 0x1001, 0x009E, /* 10base2, CSR12 0x10*/ - 0x0000, 0x009E, /* 10baseT */ - 0x0004, 0x009E, /* 10baseT-FD */ - 0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */ - 0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}}, - {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F, - 0x1B01, 0x0000, /* 10base2, CSR12 0x1B */ - 0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */ - 0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */ - 0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */ - 0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */ - }}, - {0, 0, 0, 0, {}}}; - -static const char * block_name[] = {"21140 non-MII", "21140 MII PHY", - "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"}; - -#if defined(__i386__) /* AKA get_unaligned() */ -#define get_u16(ptr) (*(u16 *)(ptr)) -#else -#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) -#endif - -static void parse_eeprom(struct net_device *dev) -{ - /* The last media info list parsed, for multiport boards. */ - static struct mediatable *last_mediatable = NULL; - static unsigned char *last_ee_data = NULL; - static int controller_index = 0; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - unsigned char *ee_data = tp->eeprom; - int i; - - tp->mtable = 0; - /* Detect an old-style (SA only) EEPROM layout: - memcmp(eedata, eedata+16, 8). */ - for (i = 0; i < 8; i ++) - if (ee_data[i] != ee_data[16+i]) - break; - if (i >= 8) { - if (ee_data[0] == 0xff) { - if (last_mediatable) { - controller_index++; - printk(KERN_INFO "%s: Controller %d of multiport board.\n", - dev->name, controller_index); - tp->mtable = last_mediatable; - ee_data = last_ee_data; - goto subsequent_board; - } else - printk(KERN_INFO "%s: Missing EEPROM, this interface may " - "not work correctly!\n", - dev->name); - return; - } - /* Do a fix-up based on the vendor half of the station address prefix. */ - for (i = 0; eeprom_fixups[i].name; i++) { - if (dev->dev_addr[0] == eeprom_fixups[i].addr0 - && dev->dev_addr[1] == eeprom_fixups[i].addr1 - && dev->dev_addr[2] == eeprom_fixups[i].addr2) { - if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) - i++; /* An Accton EN1207, not an outlaw Maxtech. */ - memcpy(ee_data + 26, eeprom_fixups[i].newtable, - sizeof(eeprom_fixups[i].newtable)); - printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" - " substitute media control info.\n", - dev->name, eeprom_fixups[i].name); - break; - } - } - if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ - printk(KERN_INFO "%s: Old style EEPROM with no media selection " - "information.\n", - dev->name); - return; - } - } - - controller_index = 0; - if (ee_data[19] > 1) { /* Multiport board. */ - last_ee_data = ee_data; - } -subsequent_board: - - if (ee_data[27] == 0) { /* No valid media table. */ - } else if (tp->chip_id == DC21041) { - unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3]; - int media = get_u16(p); - int count = p[2]; - p += 3; - - printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n", - dev->name, media, - media & 0x0800 ? "Autosense" : medianame[media & 15]); - for (i = 0; i < count; i++) { - unsigned char media_code = *p++; - if (media_code & 0x40) - p += 6; - printk(KERN_INFO "%s: 21041 media #%d, %s.\n", - dev->name, media_code & 15, medianame[media_code & 15]); - } - } else { - unsigned char *p = (void *)ee_data + ee_data[27]; - unsigned char csr12dir = 0; - int count, new_advertise = 0; - struct mediatable *mtable; - u16 media = get_u16(p); - - p += 2; - if (tp->flags & CSR12_IN_SROM) - csr12dir = *p++; - count = *p++; - mtable = (struct mediatable *) - kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf), - GFP_KERNEL); - if (mtable == NULL) - return; /* Horrible, impossible failure. */ - last_mediatable = tp->mtable = mtable; - mtable->defaultmedia = media; - mtable->leafcount = count; - mtable->csr12dir = csr12dir; - mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; - mtable->csr15dir = mtable->csr15val = 0; - - printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, - media & 0x0800 ? "Autosense" : medianame[media & 15]); - for (i = 0; i < count; i++) { - struct medialeaf *leaf = &mtable->mleaf[i]; - - if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ - leaf->type = 0; - leaf->media = p[0] & 0x3f; - leaf->leafdata = p; - if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ - mtable->has_mii = 1; - p += 4; - } else { - leaf->type = p[1]; - if (p[1] == 0x05) { - mtable->has_reset = i; - leaf->media = p[2] & 0x0f; - } else if (p[1] & 1) { - mtable->has_mii = 1; - leaf->media = 11; - } else { - mtable->has_nonmii = 1; - leaf->media = p[2] & 0x0f; - switch (leaf->media) { - case 0: new_advertise |= 0x0020; break; - case 4: new_advertise |= 0x0040; break; - case 3: new_advertise |= 0x0080; break; - case 5: new_advertise |= 0x0100; break; - case 6: new_advertise |= 0x0200; break; - } - if (p[1] == 2 && leaf->media == 0) { - if (p[2] & 0x40) { - u32 base15 = get_unaligned((u16*)&p[7]); - mtable->csr15dir = - (get_unaligned((u16*)&p[9])<<16) + base15; - mtable->csr15val = - (get_unaligned((u16*)&p[11])<<16) + base15; - } else { - mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; - mtable->csr15val = get_unaligned((u16*)&p[5])<<16; - } - } - } - leaf->leafdata = p + 2; - p += (p[0] & 0x3f) + 1; - } - if (tulip_debug > 1 && leaf->media == 11) { - unsigned char *bp = leaf->leafdata; - printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " - "sequences %d/%d long, capabilities %2.2x %2.2x.\n", - dev->name, bp[0], bp[1], bp[2 + bp[1]*2], - bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); - } - printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " - "by a %s (%d) block.\n", - dev->name, i, medianame[leaf->media], leaf->media, - block_name[leaf->type], leaf->type); - } - if (new_advertise) - tp->to_advertise = new_advertise; - } -} -/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/ - -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ -#define EE_CS 0x01 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */ -#define EE_WRITE_0 0x01 -#define EE_WRITE_1 0x05 -#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */ -#define EE_ENB (0x4800 | EE_CS) - -/* Delay between EEPROM clock transitions. - Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. - We add a bus turn-around to insure that this remains true. */ -#define eeprom_delay() inl(ee_addr) - -/* The EEPROM commands include the alway-set leading bit. */ -#define EE_READ_CMD (6) - -/* Note: this routine returns extra data bits for size detection. */ -static int __devinit read_eeprom(long ioaddr, int location, int addr_len) -{ - int i; - unsigned retval = 0; - long ee_addr = ioaddr + CSR9; - int read_cmd = location | (EE_READ_CMD << addr_len); - - outl(EE_ENB & ~EE_CS, ee_addr); - outl(EE_ENB, ee_addr); - - /* Shift the read command bits out. */ - for (i = 4 + addr_len; i >= 0; i--) { - short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - outl(EE_ENB | dataval, ee_addr); - eeprom_delay(); - outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); - } - outl(EE_ENB, ee_addr); - - for (i = 16; i > 0; i--) { - outl(EE_ENB | EE_SHIFT_CLK, ee_addr); - eeprom_delay(); - retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); - outl(EE_ENB, ee_addr); - eeprom_delay(); - } - - /* Terminate the EEPROM access. */ - outl(EE_ENB & ~EE_CS, ee_addr); - return retval; -} - -/* MII transceiver control section. - Read and write the MII registers using software-generated serial - MDIO protocol. See the MII specifications or DP83840A data sheet - for details. */ - -/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually - met by back-to-back PCI I/O cycles, but we insert a delay to avoid - "overclocking" issues or future 66Mhz PCI. */ -#define mdio_delay() inl(mdio_addr) - -/* Read and write the MII registers using software-generated serial - MDIO protocol. It is just different enough from the EEPROM protocol - to not share code. The maxium data clock rate is 2.5 Mhz. */ -#define MDIO_SHIFT_CLK 0x10000 -#define MDIO_DATA_WRITE0 0x00000 -#define MDIO_DATA_WRITE1 0x20000 -#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ -#define MDIO_ENB_IN 0x40000 -#define MDIO_DATA_READ 0x80000 - -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; - int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; - int retval = 0; - long ioaddr = dev->base_addr; - long mdio_addr = ioaddr + CSR9; - - if (tp->chip_id == LC82C168) { - int i = 1000; - outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); - inl(ioaddr + 0xA0); - inl(ioaddr + 0xA0); - while (--i > 0) - if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) - return retval & 0xffff; - return 0xffff; - } - - if (tp->chip_id == COMET) { - if (phy_id == 1) { - if (location < 7) - return inl(ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - return inl(ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - return inl(ioaddr + 0xD4 + ((location-29)<<2)); - } - return 0xffff; - } - - /* Establish sync by sending at least 32 logic ones. */ - for (i = 32; i >= 0; i--) { - outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Shift the read command bits out. */ - for (i = 15; i >= 0; i--) { - int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - - outl(MDIO_ENB | dataval, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Read the two transition, 16 data, and wire-idle bits. */ - for (i = 19; i > 0; i--) { - outl(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); - outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - return (retval>>1) & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; - int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; - long ioaddr = dev->base_addr; - long mdio_addr = ioaddr + CSR9; - - if (tp->chip_id == LC82C168) { - int i = 1000; - outl(cmd, ioaddr + 0xA0); - do - if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) - break; - while (--i > 0); - return; - } - - if (tp->chip_id == COMET) { - if (phy_id != 1) - return; - if (location < 7) - outl(value, ioaddr + 0xB4 + (location<<2)); - else if (location == 17) - outl(value, ioaddr + 0xD0); - else if (location >= 29 && location <= 31) - outl(value, ioaddr + 0xD4 + ((location-29)<<2)); - return; - } - - /* Establish sync by sending 32 logic ones. */ - for (i = 32; i >= 0; i--) { - outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Shift the command bits out. */ - for (i = 31; i >= 0; i--) { - int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - outl(MDIO_ENB | dataval, mdio_addr); - mdio_delay(); - outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - /* Clear out extra bits. */ - for (i = 2; i > 0; i--) { - outl(MDIO_ENB_IN, mdio_addr); - mdio_delay(); - outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); - mdio_delay(); - } - return; -} - - -/* The Xircom cards are picky about when certain bits in CSR6 can be - manipulated. Keith Owens . */ - -static void outl_CSR6 (struct tulip_private *tp, u32 newcsr6) -{ - long ioaddr = tp->base_addr; - const int strict_bits = 0x0060e202; - int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; - long flags; - - /* really a hw lock */ - spin_lock_irqsave (&tp->tx_lock, flags); - - if (tp->chip_id != X3201_3) - goto out_write; - - newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ - /* read 0 on the Xircom cards */ - newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ - currcsr6 = inl (ioaddr + CSR6); - if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || - ((currcsr6 & ~0x2002) == 0)) - goto out_write; - - /* make sure the transmitter and receiver are stopped first */ - currcsr6 &= ~0x2002; - while (1) { - csr5 = inl (ioaddr + CSR5); - if (csr5 == 0xffffffff) - break; /* cannot read csr5, card removed? */ - csr5_22_20 = csr5 & 0x700000; - csr5_19_17 = csr5 & 0x0e0000; - if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && - (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) - break; /* both are stopped or suspended */ - if (!--attempts) { - printk (KERN_INFO "tulip.c: outl_CSR6 too many attempts," - "csr5=0x%08x\n", csr5); - goto out_write; - } - outl (currcsr6, ioaddr + CSR6); - udelay (1); - } - -out_write: - /* now it is safe to change csr6 */ - outl (newcsr6, ioaddr + CSR6); - - spin_unlock_irqrestore (&tp->lock, flags); -} - - -static void tulip_up(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 3*HZ; - int i; - - /* Wake the chip from sleep/snooze mode. */ - if (tp->flags & HAS_ACPI) - pci_write_config_dword(tp->pdev, 0x40, 0); - - /* On some chip revs we must set the MII/SYM port before the reset!? */ - if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) - outl_CSR6 (tp, 0x00040000); - - /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ - outl(0x00000001, ioaddr + CSR0); - - /* Deassert reset. - Wait the specified 50 PCI cycles after a reset by initializing - Tx and Rx queues and the address filter list. */ - outl(tp->csr0, ioaddr + CSR0); - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq); - - if (tp->flags & MC_HASH_ONLY) { - u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); - u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); - if (tp->chip_id == AX88140) { - outl(0, ioaddr + CSR13); - outl(addr_low, ioaddr + CSR14); - outl(1, ioaddr + CSR13); - outl(addr_high, ioaddr + CSR14); - } else if (tp->chip_id == COMET) { - outl(addr_low, ioaddr + 0xA4); - outl(addr_high, ioaddr + 0xA8); - outl(0, ioaddr + 0xAC); - outl(0, ioaddr + 0xB0); - } - } else { - /* This is set_rx_mode(), but without starting the transmitter. */ - u16 *eaddrs = (u16 *)dev->dev_addr; - u16 *setup_frm = &tp->setup_frame[15*6]; - - /* 21140 bug: you must add the broadcast address. */ - memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame)); - /* Fill the final entry of the table with our physical address. */ - *setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0]; - *setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1]; - *setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2]; - /* Put the setup frame on the Tx list. */ - tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); - tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame); - tp->tx_ring[0].status = cpu_to_le32(DescOwned); - - tp->cur_tx++; - } - - outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3); - outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4); - - tp->saved_if_port = dev->if_port; - if (dev->if_port == 0) - dev->if_port = tp->default_port; - - /* Allow selecting a default media. */ - i = 0; - if (tp->mtable == NULL) - goto media_picked; - if (dev->if_port) { - int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 : - (dev->if_port == 12 ? 0 : dev->if_port); - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == looking_for) { - printk(KERN_INFO "%s: Using user-specified media %s.\n", - dev->name, medianame[dev->if_port]); - goto media_picked; - } - } - if ((tp->mtable->defaultmedia & 0x0800) == 0) { - int looking_for = tp->mtable->defaultmedia & 15; - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == looking_for) { - printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", - dev->name, medianame[looking_for]); - goto media_picked; - } - } - /* Start sensing first non-full-duplex media. */ - for (i = tp->mtable->leafcount - 1; - (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--) - ; -media_picked: - - tp->csr6 = 0; - tp->cur_index = i; - tp->nwayset = 0; - if (dev->if_port == 0 && tp->chip_id == DC21041) { - tp->nway = 1; - } - if (dev->if_port == 0 && tp->chip_id == DC21142) { - if (tp->mii_cnt) { - select_media(dev, 1); - if (tulip_debug > 1) - printk(KERN_INFO "%s: Using MII transceiver %d, status " - "%4.4x.\n", - dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1)); - outl_CSR6(tp, 0x82020000); - tp->csr6 = 0x820E0000; - dev->if_port = 11; - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - } else - t21142_start_nway(dev); - } else if (tp->chip_id == PNIC2) { - t21142_start_nway(dev); - } else if (tp->chip_id == LC82C168 && ! tp->medialock) { - if (tp->mii_cnt) { - dev->if_port = 11; - tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0); - outl(0x0001, ioaddr + CSR15); - } else if (inl(ioaddr + CSR5) & TPLnkPass) - pnic_do_nway(dev); - else { - /* Start with 10mbps to do autonegotiation. */ - outl(0x32, ioaddr + CSR12); - tp->csr6 = 0x00420000; - outl(0x0001B078, ioaddr + 0xB8); - outl(0x0201B078, ioaddr + 0xB8); - next_tick = 1*HZ; - } - } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) - && ! tp->medialock) { - dev->if_port = 0; - tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); - outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); - } else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) { - /* Provided by BOLO, Macronix - 12/10/1998. */ - dev->if_port = 0; - tp->csr6 = 0x01a80200; - outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80); - outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0); - } else if (tp->chip_id == DC21143 && - media_cap[dev->if_port] & MediaIsMII) { - /* We must reset the media CSRs when we force-select MII mode. */ - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - outl(0x0008, ioaddr + CSR15); - } else if (tp->chip_id == COMET) { - dev->if_port = 0; - tp->csr6 = 0x00040000; - } else if (tp->chip_id == AX88140) { - tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100; - } else - select_media(dev, 1); - - /* Start the chip's Tx to process setup frame. */ - outl_CSR6(tp, tp->csr6); - outl_CSR6(tp, tp->csr6 | 0x2000); - - /* Enable interrupts by setting the interrupt mask. */ - outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); - outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); - outl_CSR6(tp, tp->csr6 | 0x2002); - outl(0, ioaddr + CSR2); /* Rx poll demand */ - - if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n", - dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), - inl(ioaddr + CSR6)); - } - /* Set the timer to switch to check for link beat and perhaps switch - to an alternate media type. */ - init_timer(&tp->timer); - tp->timer.expires = RUN_AT(next_tick); - tp->timer.data = (unsigned long)dev; - tp->timer.function = tulip_tbl[tp->chip_id].media_timer; - add_timer(&tp->timer); - - netif_device_attach(dev); -} - - -static int -tulip_open(struct net_device *dev) -{ - MOD_INC_USE_COUNT; - - if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) { - MOD_DEC_USE_COUNT; - return -EBUSY; - } - - tulip_init_ring (dev); - - tulip_up (dev); - - return 0; -} - - -/* Set up the transceiver control registers for the selected media type. */ -static void select_media(struct net_device *dev, int startup) -{ - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - struct mediatable *mtable = tp->mtable; - u32 new_csr6; - int i; - - if (mtable) { - struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; - unsigned char *p = mleaf->leafdata; - switch (mleaf->type) { - case 0: /* 21140 non-MII xcvr. */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver" - " with control setting %2.2x.\n", - dev->name, p[1]); - dev->if_port = p[0]; - if (startup) - outl(mtable->csr12dir | 0x100, ioaddr + CSR12); - outl(p[1], ioaddr + CSR12); - new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18); - break; - case 2: case 4: { - u16 setup[5]; - u32 csr13val, csr14val, csr15dir, csr15val; - for (i = 0; i < 5; i++) - setup[i] = get_u16(&p[i*2 + 1]); - - dev->if_port = p[0] & 15; - if (media_cap[dev->if_port] & MediaAlwaysFD) - tp->full_duplex = 1; - - if (startup && mtable->has_reset) { - struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset]; - unsigned char *rst = rleaf->leafdata; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Resetting the transceiver.\n", - dev->name); - for (i = 0; i < rst[0]; i++) - outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15); - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control " - "%4.4x/%4.4x.\n", - dev->name, medianame[dev->if_port], setup[0], setup[1]); - if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ - csr13val = setup[0]; - csr14val = setup[1]; - csr15dir = (setup[3]<<16) | setup[2]; - csr15val = (setup[4]<<16) | setup[2]; - outl(0, ioaddr + CSR13); - outl(csr14val, ioaddr + CSR14); - outl(csr15dir, ioaddr + CSR15); /* Direction */ - outl(csr15val, ioaddr + CSR15); /* Data */ - outl(csr13val, ioaddr + CSR13); - } else { - csr13val = 1; - csr14val = 0x0003FF7F; - csr15dir = (setup[0]<<16) | 0x0008; - csr15val = (setup[1]<<16) | 0x0008; - if (dev->if_port <= 4) - csr14val = t21142_csr14[dev->if_port]; - if (startup) { - outl(0, ioaddr + CSR13); - outl(csr14val, ioaddr + CSR14); - } - outl(csr15dir, ioaddr + CSR15); /* Direction */ - outl(csr15val, ioaddr + CSR15); /* Data */ - if (startup) outl(csr13val, ioaddr + CSR13); - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Setting CSR15 to %8.8x/%8.8x.\n", - dev->name, csr15dir, csr15val); - if (mleaf->type == 4) - new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18); - else - new_csr6 = 0x82420000; - break; - } - case 1: case 3: { - int phy_num = p[0]; - int init_length = p[1]; - u16 *misc_info; - u16 to_advertise; - - dev->if_port = 11; - new_csr6 = 0x020E0000; - if (mleaf->type == 3) { /* 21142 */ - u16 *init_sequence = (u16*)(p+2); - u16 *reset_sequence = &((u16*)(p+3))[init_length]; - int reset_length = p[2 + init_length*2]; - misc_info = reset_sequence + reset_length; - if (startup) - for (i = 0; i < reset_length; i++) - outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); - for (i = 0; i < init_length; i++) - outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); - } else { - u8 *init_sequence = p + 2; - u8 *reset_sequence = p + 3 + init_length; - int reset_length = p[2 + init_length]; - misc_info = (u16*)(reset_sequence + reset_length); - if (startup) { - outl(mtable->csr12dir | 0x100, ioaddr + CSR12); - for (i = 0; i < reset_length; i++) - outl(reset_sequence[i], ioaddr + CSR12); - } - for (i = 0; i < init_length; i++) - outl(init_sequence[i], ioaddr + CSR12); - } - to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1; - tp->advertising[phy_num] = to_advertise; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n", - dev->name, to_advertise, phy_num, tp->phys[phy_num]); - /* Bogus: put in by a committee? */ - mdio_write(dev, tp->phys[phy_num], 4, to_advertise); - break; - } - default: - printk(KERN_DEBUG "%s: Invalid media table selection %d.\n", - dev->name, mleaf->type); - new_csr6 = 0x020E0000; - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", - dev->name, medianame[dev->if_port], - inl(ioaddr + CSR12) & 0xff); - } else if (tp->chip_id == DC21041) { - int port = dev->if_port <= 4 ? dev->if_port : 0; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", - dev->name, medianame[port == 3 ? 12: port], - inl(ioaddr + CSR12)); - outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ - outl(t21041_csr14[port], ioaddr + CSR14); - outl(t21041_csr15[port], ioaddr + CSR15); - outl(t21041_csr13[port], ioaddr + CSR13); - new_csr6 = 0x80020000; - } else if (tp->chip_id == LC82C168) { - if (startup && ! tp->medialock) - dev->if_port = tp->mii_cnt ? 11 : 0; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n", - dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]); - if (tp->mii_cnt) { - new_csr6 = 0x810C0000; - outl(0x0001, ioaddr + CSR15); - outl(0x0201B07A, ioaddr + 0xB8); - } else if (startup) { - /* Start with 10mbps to do autonegotiation. */ - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x0001B078, ioaddr + 0xB8); - outl(0x0201B078, ioaddr + 0xB8); - } else if (dev->if_port == 3 || dev->if_port == 5) { - outl(0x33, ioaddr + CSR12); - new_csr6 = 0x01860000; - /* Trigger autonegotiation. */ - outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8); - } else { - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x1F078, ioaddr + 0xB8); - } - } else if (tp->chip_id == DC21040) { /* 21040 */ - /* Turn on the xcvr interface. */ - int csr12 = inl(ioaddr + CSR12); - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", - dev->name, medianame[dev->if_port], csr12); - if (media_cap[dev->if_port] & MediaAlwaysFD) - tp->full_duplex = 1; - new_csr6 = 0x20000; - /* Set the full duplux match frame. */ - outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11); - outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ - if (t21040_csr13[dev->if_port] & 8) { - outl(0x0705, ioaddr + CSR14); - outl(0x0006, ioaddr + CSR15); - } else { - outl(0xffff, ioaddr + CSR14); - outl(0x0000, ioaddr + CSR15); - } - outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13); - } else { /* Unknown chip type with no media table. */ - if (tp->default_port == 0) - dev->if_port = tp->mii_cnt ? 11 : 3; - if (media_cap[dev->if_port] & MediaIsMII) { - new_csr6 = 0x020E0000; - } else if (media_cap[dev->if_port] & MediaIsFx) { - new_csr6 = 0x028600000; - } else - new_csr6 = 0x038600000; - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No media description table, assuming " - "%s transceiver, CSR12 %2.2x.\n", - dev->name, medianame[dev->if_port], - inl(ioaddr + CSR12)); - } - - tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0); - return; -} - -/* - Check the MII negotiated duplex, and change the CSR6 setting if - required. - Return 0 if everything is OK. - Return < 0 if the transceiver is missing or has no link beat. - */ -static int check_duplex(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int mii_reg1, mii_reg5, negotiated, duplex; - - if (tp->full_duplex_lock) - return 0; - mii_reg1 = mdio_read(dev, tp->phys[0], 1); - mii_reg5 = mdio_read(dev, tp->phys[0], 5); - if (tulip_debug > 1) - printk(KERN_INFO "%s: MII status %4.4x, Link partner report " - "%4.4x.\n", dev->name, mii_reg1, mii_reg5); - if (mii_reg1 == 0xffff) - return -2; - if ((mii_reg1 & 0x0004) == 0) { - int new_reg1 = mdio_read(dev, tp->phys[0], 1); - if ((new_reg1 & 0x0004) == 0) { - if (tulip_debug > 1) - printk(KERN_INFO "%s: No link beat on the MII interface," - " status %4.4x.\n", dev->name, new_reg1); - return -1; - } - } - negotiated = mii_reg5 & tp->advertising[0]; - duplex = ((negotiated & 0x0300) == 0x0100 - || (negotiated & 0x00C0) == 0x0040); - /* 100baseTx-FD or 10T-FD, but not 100-HD */ - if (tp->full_duplex != duplex) { - tp->full_duplex = duplex; - if (negotiated & 0x038) /* 100mbps. */ - tp->csr6 &= ~0x00400000; - if (tp->full_duplex) tp->csr6 |= 0x0200; - else tp->csr6 &= ~0x0200; - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - if (tulip_debug > 0) - printk(KERN_INFO "%s: Setting %s-duplex based on MII" - "#%d link partner capability of %4.4x.\n", - dev->name, tp->full_duplex ? "full" : "half", - tp->phys[0], mii_reg5); - return 1; - } - return 0; -} - -static void tulip_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - u32 csr12 = inl(ioaddr + CSR12); - int next_tick = 2*HZ; - - if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode" - " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n", - dev->name, medianame[dev->if_port], inl(ioaddr + CSR5), - inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13), - inl(ioaddr + CSR14), inl(ioaddr + CSR15)); - } - switch (tp->chip_id) { - case DC21040: - if (!tp->medialock && csr12 & 0x0002) { /* Network error */ - printk(KERN_INFO "%s: No link beat found.\n", - dev->name); - dev->if_port = (dev->if_port == 2 ? 0 : 2); - select_media(dev, 0); - dev->trans_start = jiffies; - } - break; - case DC21041: - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", - dev->name, csr12); - if (tp->medialock) break; - switch (dev->if_port) { - case 0: case 3: case 4: - if (csr12 & 0x0004) { /*LnkFail */ - /* 10baseT is dead. Check for activity on alternate port. */ - tp->mediasense = 1; - if (csr12 & 0x0200) - dev->if_port = 2; - else - dev->if_port = 1; - printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", - dev->name, medianame[dev->if_port]); - outl(0, ioaddr + CSR13); /* Reset */ - outl(t21041_csr14[dev->if_port], ioaddr + CSR14); - outl(t21041_csr15[dev->if_port], ioaddr + CSR15); - outl(t21041_csr13[dev->if_port], ioaddr + CSR13); - next_tick = 10*HZ; /* 2.4 sec. */ - } else - next_tick = 30*HZ; - break; - case 1: /* 10base2 */ - case 2: /* AUI */ - if (csr12 & 0x0100) { - next_tick = (30*HZ); /* 30 sec. */ - tp->mediasense = 0; - } else if ((csr12 & 0x0004) == 0) { - printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", - dev->name); - dev->if_port = 0; - select_media(dev, 0); - next_tick = (24*HZ)/10; /* 2.4 sec. */ - } else if (tp->mediasense || (csr12 & 0x0002)) { - dev->if_port = 3 - dev->if_port; /* Swap ports. */ - select_media(dev, 0); - next_tick = 20*HZ; - } else { - next_tick = 20*HZ; - } - break; - } - break; - case DC21140: case DC21142: case MX98713: case COMPEX9881: default: { - struct medialeaf *mleaf; - unsigned char *p; - if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */ - /* Not much that can be done. - Assume this a generic MII or SYM transceiver. */ - next_tick = 60*HZ; - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x " - "CSR12 0x%2.2x.\n", - dev->name, inl(ioaddr + CSR6), csr12 & 0xff); - break; - } - mleaf = &tp->mtable->mleaf[tp->cur_index]; - p = mleaf->leafdata; - switch (mleaf->type) { - case 0: case 4: { - /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */ - int offset = mleaf->type == 4 ? 5 : 2; - s8 bitnum = p[offset]; - if (p[offset+1] & 0x80) { - if (tulip_debug > 1) - printk(KERN_DEBUG"%s: Transceiver monitor tick " - "CSR12=%#2.2x, no media sense.\n", - dev->name, csr12); - if (mleaf->type == 4) { - if (mleaf->media == 3 && (csr12 & 0x02)) - goto select_next_media; - } - break; - } - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x" - " bit %d is %d, expecting %d.\n", - dev->name, csr12, (bitnum >> 1) & 7, - (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, - (bitnum >= 0)); - /* Check that the specified bit has the proper value. */ - if ((bitnum < 0) != - ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, - medianame[mleaf->media]); - if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */ - goto actually_mii; - break; - } - if (tp->medialock) - break; - select_next_media: - if (--tp->cur_index < 0) { - /* We start again, but should instead look for default. */ - tp->cur_index = tp->mtable->leafcount - 1; - } - dev->if_port = tp->mtable->mleaf[tp->cur_index].media; - if (media_cap[dev->if_port] & MediaIsFD) - goto select_next_media; /* Skip FD entries. */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: No link beat on media %s," - " trying transceiver type %s.\n", - dev->name, medianame[mleaf->media & 15], - medianame[tp->mtable->mleaf[tp->cur_index].media]); - select_media(dev, 0); - /* Restart the transmit process. */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - next_tick = (24*HZ)/10; - break; - } - case 1: case 3: /* 21140, 21142 MII */ - actually_mii: - check_duplex(dev); - next_tick = 60*HZ; - break; - case 2: /* 21142 serial block has no link beat. */ - default: - break; - } - } - break; - } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - - -/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list - of available transceivers. */ -static void t21142_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr12 = inl(ioaddr + CSR12); - int next_tick = 60*HZ; - int new_csr6 = 0; - - if (tulip_debug > 2) - printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n", - dev->name, csr12, medianame[dev->if_port]); - if (media_cap[dev->if_port] & MediaIsMII) { - check_duplex(dev); - next_tick = 60*HZ; - } else if (tp->nwayset) { - /* Don't screw up a negotiated session! */ - if (tulip_debug > 1) - printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n", - dev->name, medianame[dev->if_port], csr12); - } else if (tp->medialock) { - ; - } else if (dev->if_port == 3) { - if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */ - if (tulip_debug > 1) - printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, " - "trying NWay.\n", dev->name, csr12); - t21142_start_nway(dev); - next_tick = 3*HZ; - } - } else if ((csr12 & 0x7000) != 0x5000) { - /* Negotiation failed. Search media types. */ - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n", - dev->name, csr12); - if (!(csr12 & 4)) { /* 10mbps link beat good. */ - new_csr6 = 0x82420000; - dev->if_port = 0; - outl(0, ioaddr + CSR13); - outl(0x0003FFFF, ioaddr + CSR14); - outw(t21142_csr15[dev->if_port], ioaddr + CSR15); - outl(t21142_csr13[dev->if_port], ioaddr + CSR13); - } else { - /* Select 100mbps port to check for link beat. */ - new_csr6 = 0x83860000; - dev->if_port = 3; - outl(0, ioaddr + CSR13); - outl(0x0003FF7F, ioaddr + CSR14); - outw(8, ioaddr + CSR15); - outl(1, ioaddr + CSR13); - } - if (tulip_debug > 1) - printk(KERN_INFO"%s: Testing new 21143 media %s.\n", - dev->name, medianame[dev->if_port]); - if (new_csr6 != (tp->csr6 & ~0x00D5)) { - tp->csr6 &= 0x00D5; - tp->csr6 |= new_csr6; - outl(0x0301, ioaddr + CSR12); - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - } - next_tick = 3*HZ; - } - - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - - -static void t21142_start_nway(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr14 = ((tp->to_advertise & 0x0780) << 9) | - ((tp->to_advertise&0x0020)<<1) | 0xffbf; - - dev->if_port = 0; - tp->nway = tp->mediasense = 1; - tp->nwayset = tp->lpar = 0; - if (debug > 1) - printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n", - dev->name, csr14); - outl(0x0001, ioaddr + CSR13); - outl(csr14, ioaddr + CSR14); - tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); - outl_CSR6(tp, tp->csr6); - if (tp->mtable && tp->mtable->csr15dir) { - outl(tp->mtable->csr15dir, ioaddr + CSR15); - outl(tp->mtable->csr15val, ioaddr + CSR15); - } else - outw(0x0008, ioaddr + CSR15); - outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ -} - - -static void t21142_lnk_change(struct net_device *dev, int csr5) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr12 = inl(ioaddr + CSR12); - - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, " - "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14)); - - /* If NWay finished and we have a negotiated partner capability. */ - if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) { - int setup_done = 0; - int negotiated = tp->to_advertise & (csr12 >> 16); - tp->lpar = csr12 >> 16; - tp->nwayset = 1; - if (negotiated & 0x0100) dev->if_port = 5; - else if (negotiated & 0x0080) dev->if_port = 3; - else if (negotiated & 0x0040) dev->if_port = 4; - else if (negotiated & 0x0020) dev->if_port = 0; - else { - tp->nwayset = 0; - if ((csr12 & 2) == 0 && (tp->to_advertise & 0x0180)) - dev->if_port = 3; - } - tp->full_duplex = (media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0; - - if (tulip_debug > 1) { - if (tp->nwayset) - printk(KERN_INFO "%s: Switching to %s based on link " - "negotiation %4.4x & %4.4x = %4.4x.\n", - dev->name, medianame[dev->if_port], tp->to_advertise, - tp->lpar, negotiated); - else - printk(KERN_INFO "%s: Autonegotiation failed, using %s," - " link beat status %4.4x.\n", - dev->name, medianame[dev->if_port], csr12); - } - - if (tp->mtable) { - int i; - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == dev->if_port) { - tp->cur_index = i; - select_media(dev, 0); - setup_done = 1; - break; - } - } - if ( ! setup_done) { - tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000; - if (tp->full_duplex) - tp->csr6 |= 0x0200; - outl(1, ioaddr + CSR13); - } -#if 0 /* Restart shouldn't be needed. */ - outl_CSR6(tp, tp->csr6 | 0x0000); - if (debug > 2) - printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", - dev->name, inl(ioaddr + CSR5)); -#endif - outl_CSR6(tp, tp->csr6 | 0x2002); - if (debug > 2) - printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n", - dev->name, tp->csr6, inl(ioaddr + CSR6), - inl(ioaddr + CSR12)); - } else if ((tp->nwayset && (csr5 & 0x08000000) - && (dev->if_port == 3 || dev->if_port == 5) - && (csr12 & 2) == 2) || - (tp->nway && (csr5 & (TPLnkFail)))) { - /* Link blew? Maybe restart NWay. */ - del_timer(&tp->timer); - t21142_start_nway(dev); - tp->timer.expires = RUN_AT(3*HZ); - add_timer(&tp->timer); - } else if (dev->if_port == 3 || dev->if_port == 5) { - if (tulip_debug > 1) - printk(KERN_INFO"%s: 21143 %s link beat %s.\n", - dev->name, medianame[dev->if_port], - (csr12 & 2) ? "failed" : "good"); - if ((csr12 & 2) && ! tp->medialock) { - del_timer(&tp->timer); - t21142_start_nway(dev); - tp->timer.expires = RUN_AT(3*HZ); - add_timer(&tp->timer); - } - } else if (dev->if_port == 0 || dev->if_port == 4) { - if ((csr12 & 4) == 0) - printk(KERN_INFO"%s: 21143 10baseT link beat good.\n", - dev->name); - } else if (!(csr12 & 4)) { /* 10mbps link beat good. */ - if (tulip_debug) - printk(KERN_INFO"%s: 21143 10mbps sensed media.\n", - dev->name); - dev->if_port = 0; - } else if (tp->nwayset) { - if (tulip_debug) - printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n", - dev->name, medianame[dev->if_port], tp->csr6); - } else { /* 100mbps link beat good. */ - if (tulip_debug) - printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n", - dev->name); - dev->if_port = 3; - tp->csr6 = 0x83860000; - outl(0x0003FF7F, ioaddr + CSR14); - outl(0x0301, ioaddr + CSR12); - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - } -} - - -static void mxic_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - - if (tulip_debug > 3) { - printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name, - inl(ioaddr + CSR12)); - } - if (next_tick) { - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); - } -} - - -static void pnic_do_nway(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - u32 phy_reg = inl(ioaddr + 0xB8); - u32 new_csr6 = tp->csr6 & ~0x40C40200; - - if (phy_reg & 0x78000000) { /* Ignore baseT4 */ - if (phy_reg & 0x20000000) dev->if_port = 5; - else if (phy_reg & 0x40000000) dev->if_port = 3; - else if (phy_reg & 0x10000000) dev->if_port = 4; - else if (phy_reg & 0x08000000) dev->if_port = 0; - tp->nwayset = 1; - new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000; - outl(0x32 | (dev->if_port & 1), ioaddr + CSR12); - if (dev->if_port & 1) - outl(0x1F868, ioaddr + 0xB8); - if (phy_reg & 0x30000000) { - tp->full_duplex = 1; - new_csr6 |= 0x00000200; - } - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n", - dev->name, phy_reg, medianame[dev->if_port]); - if (tp->csr6 != new_csr6) { - tp->csr6 = new_csr6; - /* Restart Tx */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - dev->trans_start = jiffies; - } - } -} - - -static void pnic_lnk_change(struct net_device *dev, int csr5) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int phy_reg = inl(ioaddr + 0xB8); - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n", - dev->name, phy_reg, csr5); - if (inl(ioaddr + CSR5) & TPLnkFail) { - outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); - if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { - tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); - outl_CSR6(tp, tp->csr6); - outl(0x30, ioaddr + CSR12); - outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ - dev->trans_start = jiffies; - } - } else if (inl(ioaddr + CSR5) & TPLnkPass) { - pnic_do_nway(dev); - outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7); - } -} - - -static void pnic_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - - if (media_cap[dev->if_port] & MediaIsMII) { - if (check_duplex(dev) > 0) - next_tick = 3*HZ; - } else { - int csr12 = inl(ioaddr + CSR12); - int new_csr6 = tp->csr6 & ~0x40C40200; - int phy_reg = inl(ioaddr + 0xB8); - int csr5 = inl(ioaddr + CSR5); - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s " - "CSR5 %8.8x.\n", - dev->name, phy_reg, medianame[dev->if_port], csr5); - if (phy_reg & 0x04000000) { /* Remote link fault */ - outl(0x0201F078, ioaddr + 0xB8); - next_tick = 1*HZ; - tp->nwayset = 0; - } else if (phy_reg & 0x78000000) { /* Ignore baseT4 */ - pnic_do_nway(dev); - next_tick = 60*HZ; - } else if (csr5 & TPLnkFail) { /* 100baseTx link beat */ - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, " - "CSR5 %8.8x, PHY %3.3x.\n", - dev->name, medianame[dev->if_port], csr12, - inl(ioaddr + CSR5), inl(ioaddr + 0xB8)); - next_tick = 3*HZ; - if (tp->medialock) { - } else if (tp->nwayset && (dev->if_port & 1)) { - next_tick = 1*HZ; - } else if (dev->if_port == 0) { - dev->if_port = 3; - outl(0x33, ioaddr + CSR12); - new_csr6 = 0x01860000; - outl(0x1F868, ioaddr + 0xB8); - } else { - dev->if_port = 0; - outl(0x32, ioaddr + CSR12); - new_csr6 = 0x00420000; - outl(0x1F078, ioaddr + 0xB8); - } - if (tp->csr6 != new_csr6) { - tp->csr6 = new_csr6; - /* Restart Tx */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - dev->trans_start = jiffies; - if (tulip_debug > 1) - printk(KERN_INFO "%s: Changing PNIC configuration to %s " - "%s-duplex, CSR6 %8.8x.\n", - dev->name, medianame[dev->if_port], - tp->full_duplex ? "full" : "half", new_csr6); - } - } - } - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - -static void comet_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int next_tick = 60*HZ; - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability " - "%4.4x.\n", - dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8)); - tp->timer.expires = RUN_AT(next_tick); - add_timer(&tp->timer); -} - -static void tulip_tx_timeout(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (media_cap[dev->if_port] & MediaIsMII) { - /* Do nothing -- the media monitor should handle this. */ - if (tulip_debug > 1) - printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", - dev->name); - } else if (tp->chip_id == DC21040) { - if ( !tp->medialock && inl(ioaddr + CSR12) & 0x0002) { - dev->if_port = (dev->if_port == 2 ? 0 : 2); - printk(KERN_INFO "%s: transmit timed out, switching to " - "%s.\n", - dev->name, medianame[dev->if_port]); - select_media(dev, 0); - } - dev->trans_start = jiffies; - return; - } else if (tp->chip_id == DC21041) { - int csr12 = inl(ioaddr + CSR12); - - printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, " - "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), csr12, - inl(ioaddr + CSR13), inl(ioaddr + CSR14)); - tp->mediasense = 1; - if ( ! tp->medialock) { - if (dev->if_port == 1 || dev->if_port == 2) - if (csr12 & 0x0004) { - dev->if_port = 2 - dev->if_port; - } else - dev->if_port = 0; - else - dev->if_port = 1; - select_media(dev, 0); - } - } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 - || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) { - printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " - "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), - inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); - if ( ! tp->medialock && tp->mtable) { - do - --tp->cur_index; - while (tp->cur_index >= 0 - && (media_cap[tp->mtable->mleaf[tp->cur_index].media] - & MediaIsFD)); - if (--tp->cur_index < 0) { - /* We start again, but should instead look for default. */ - tp->cur_index = tp->mtable->leafcount - 1; - } - select_media(dev, 0); - printk(KERN_WARNING "%s: transmit timed out, switching to %s " - "media.\n", dev->name, medianame[dev->if_port]); - } - } else { - printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 " - "%8.8x, resetting...\n", - dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); - dev->if_port = 0; - } - -#if defined(way_too_many_messages) - if (tulip_debug > 3) { - int i; - for (i = 0; i < RX_RING_SIZE; i++) { - u8 *buf = (u8 *)(tp->rx_ring[i].buffer1); - int j; - printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x " - "%2.2x %2.2x %2.2x.\n", - i, (unsigned int)tp->rx_ring[i].status, - (unsigned int)tp->rx_ring[i].length, - (unsigned int)tp->rx_ring[i].buffer1, - (unsigned int)tp->rx_ring[i].buffer2, - buf[0], buf[1], buf[2]); - for (j = 0; buf[j] != 0xee && j < 1600; j++) - if (j < 100) printk(" %2.2x", buf[j]); - printk(" j=%d.\n", j); - } - printk(KERN_DEBUG " Rx ring %8.8x: ", (int)tp->rx_ring); - for (i = 0; i < RX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); - printk("\n" KERN_DEBUG " Tx ring %8.8x: ", (int)tp->tx_ring); - for (i = 0; i < TX_RING_SIZE; i++) - printk(" %8.8x", (unsigned int)tp->tx_ring[i].status); - printk("\n"); - } -#endif - - /* Stop and restart the chip's Tx processes . */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - /* Trigger an immediate transmit demand. */ - outl(0, ioaddr + CSR1); - - dev->trans_start = jiffies; - tp->stats.tx_errors++; - return; -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void tulip_init_ring(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; - - tp->tx_full = 0; - tp->cur_rx = tp->cur_tx = 0; - tp->dirty_rx = tp->dirty_tx = 0; - tp->susp_rx = 0; - tp->ttimer = 0; - tp->nir = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - tp->rx_ring[i].status = 0x00000000; - tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); - tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]); - tp->rx_skbuff[i] = NULL; - } - /* Mark the last entry as wrapping the ring. */ - tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP); - tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]); - - for (i = 0; i < RX_RING_SIZE; i++) { - /* Note the receive buffer must be longword aligned. - dev_alloc_skb() provides 16 byte alignment. But do *not* - use skb_reserve() to align the IP header! */ - struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); - tp->rx_skbuff[i] = skb; - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */ - tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail); - } - tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - - /* The Tx buffer descriptor is filled in as needed, but we - do need to clear the ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { - tp->tx_skbuff[i] = 0; - tp->tx_ring[i].status = 0x00000000; - tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]); - } - tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]); -} - -static int -tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int entry; - u32 flag; - unsigned long cpuflags; - - /* Caution: the write order is important here, set the field - with the ownership bits last. */ - - spin_lock_irqsave(&tp->tx_lock, cpuflags); - - /* Calculate the next Tx descriptor entry. */ - entry = tp->cur_tx % TX_RING_SIZE; - - tp->tx_skbuff[entry] = skb; - tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data); - - if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ - flag = 0x60000000; /* No interrupt */ - } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { - flag = 0xe0000000; /* Tx-done intr. */ - } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { - flag = 0x60000000; /* No Tx-done intr. */ - } else { /* Leave room for set_rx_mode() to fill entries. */ - tp->tx_full = 1; - flag = 0xe0000000; /* Tx-done intr. */ - netif_stop_queue(dev); - } - if (entry == TX_RING_SIZE-1) - flag = 0xe0000000 | DESC_RING_WRAP; - - tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag); - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); - tp->cur_tx++; - spin_unlock_irqrestore(&tp->tx_lock, cpuflags); - - /* Trigger an immediate transmit demand. */ - outl(0, dev->base_addr + CSR1); - - dev->trans_start = jiffies; - - return 0; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr5; - int entry; - int missed; - int rx = 0; - int tx = 0; - int oi = 0; - int maxrx = RX_RING_SIZE; - int maxtx = TX_RING_SIZE; - int maxoi = TX_RING_SIZE; - - tp->nir++; - - do { - csr5 = inl(ioaddr + CSR5); - /* Acknowledge all of the current interrupt sources ASAP. */ - outl(csr5 & 0x0001ffff, ioaddr + CSR5); - - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", - dev->name, csr5, inl(dev->base_addr + CSR5)); - - if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) - break; - - if (csr5 & (RxIntr | RxNoBuf)) { - rx += tulip_rx(dev); - tulip_refill_rx(dev); - } - - if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { - unsigned int dirty_tx; - - spin_lock(&tp->tx_lock); - - for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; - dirty_tx++) { - int entry = dirty_tx % TX_RING_SIZE; - int status = le32_to_cpu(tp->tx_ring[entry].status); - - if (status < 0) - break; /* It still has not been Txed */ - /* Check for Rx filter setup frames. */ - if (tp->tx_skbuff[entry] == NULL) - continue; - - if (status & 0x8000) { - /* There was an major error, log it. */ -#ifndef final_version - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", - dev->name, status); -#endif - tp->stats.tx_errors++; - if (status & 0x4104) tp->stats.tx_aborted_errors++; - if (status & 0x0C00) tp->stats.tx_carrier_errors++; - if (status & 0x0200) tp->stats.tx_window_errors++; - if (status & 0x0002) tp->stats.tx_fifo_errors++; - if ((status & 0x0080) && tp->full_duplex == 0) - tp->stats.tx_heartbeat_errors++; -#ifdef ETHER_STATS - if (status & 0x0100) tp->stats.collisions16++; -#endif - } else { -#ifdef ETHER_STATS - if (status & 0x0001) tp->stats.tx_deferred++; -#endif - tp->stats.tx_bytes += tp->tx_skbuff[entry]->len; - tp->stats.collisions += (status >> 3) & 15; - tp->stats.tx_packets++; - } - - /* Free the original skb. */ - dev_kfree_skb_irq(tp->tx_skbuff[entry]); - tp->tx_skbuff[entry] = 0; - tx++; - } - -#ifndef final_version - if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { - printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, tp->cur_tx, tp->tx_full); - dirty_tx += TX_RING_SIZE; - } -#endif - - if (tp->tx_full && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) { - /* The ring is no longer full, clear tbusy. */ - tp->tx_full = 0; - netif_wake_queue(dev); - } - - tp->dirty_tx = dirty_tx; - if (csr5 & TxDied) { - if (tulip_debug > 2) - printk(KERN_WARNING "%s: The transmitter stopped." - " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", - dev->name, csr5, inl(ioaddr + CSR6), tp->csr6); - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - } - spin_unlock(&tp->tx_lock); - } - - /* Log errors. */ - if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ - if (csr5 == 0xffffffff) - break; - if (csr5 & TxJabber) tp->stats.tx_errors++; - if (csr5 & TxFIFOUnderflow) { - if ((tp->csr6 & 0xC000) != 0xC000) - tp->csr6 += 0x4000; /* Bump up the Tx threshold */ - else - tp->csr6 |= 0x00200000; /* Store-n-forward. */ - /* Restart the transmit process. */ - outl_CSR6(tp, tp->csr6 | 0x0002); - outl_CSR6(tp, tp->csr6 | 0x2002); - outl(0, ioaddr + CSR1); - } - if (csr5 & RxDied) { /* Missed a Rx frame. */ - tp->stats.rx_errors++; - tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - outl_CSR6(tp, tp->csr6 | 0x2002); - } - if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { - if (tp->link_change) - (tp->link_change)(dev, csr5); - } - if (csr5 & SytemError) { - printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir); - } - /* Clear all error sources, included undocumented ones! */ - outl(0x0800f7ba, ioaddr + CSR5); - oi++; - } - if (csr5 & TimerInt) { -#if 0 - if (tulip_debug > 2) - printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n", - dev->name, csr5); - outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); -#endif - tp->ttimer = 0; - oi++; - } - if (tx > maxtx || rx > maxrx || oi > maxoi) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: Too much work during an interrupt, " - "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi); - /* Acknowledge all interrupt sources. */ -#if 0 - /* Clear all interrupting sources, set timer to re-enable. */ - outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt, - ioaddr + CSR7); - outl(12, ioaddr + CSR11); - tp->ttimer = 1; -#endif - break; - } - } while (1); - - tulip_refill_rx(dev); - - /* check if we card is in suspend mode */ - entry = tp->dirty_rx % RX_RING_SIZE; - if (tp->rx_skbuff[entry] == NULL) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx); - if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir); - outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt, - ioaddr + CSR7); - outl(TimerInt, ioaddr + CSR5); - outl(12, ioaddr + CSR11); - tp->ttimer = 1; - } - } - - if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) { - tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; - } - - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", - dev->name, inl(ioaddr + CSR5)); - -} - -static int tulip_refill_rx(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int entry; - int refilled = 0; - - /* Refill the Rx ring buffers. */ - for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { - entry = tp->dirty_rx % RX_RING_SIZE; - if (tp->rx_skbuff[entry] == NULL) { - struct sk_buff *skb; - skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ); - if (skb == NULL) - break; - skb->dev = dev; /* Mark as being used by this device. */ - tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail); - refilled++; - } - tp->rx_ring[entry].status = cpu_to_le32(DescOwned); - } - return refilled; -} - -static int tulip_rx(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int entry = tp->cur_rx % RX_RING_SIZE; - int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; - int received = 0; - - if (tulip_debug > 4) - printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, - tp->rx_ring[entry].status); - /* If we own the next entry, it is a new packet. Send it up. */ - while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { - s32 status = le32_to_cpu(tp->rx_ring[entry].status); - - if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n", - dev->name, entry, status); - if (--rx_work_limit < 0) - break; - if ((status & 0x38008300) != 0x0300) { - if ((status & 0x38000300) != 0x0300) { - /* Ingore earlier buffers. */ - if ((status & 0xffff) != 0x7fff) { - if (tulip_debug > 1) - printk(KERN_WARNING "%s: Oversized Ethernet frame " - "spanned multiple buffers, status %8.8x!\n", - dev->name, status); - tp->stats.rx_length_errors++; - } - } else if (status & RxDescFatalErr) { - /* There was a fatal error. */ - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", - dev->name, status); - tp->stats.rx_errors++; /* end of a packet.*/ - if (status & 0x0890) tp->stats.rx_length_errors++; - if (status & 0x0004) tp->stats.rx_frame_errors++; - if (status & 0x0002) tp->stats.rx_crc_errors++; - if (status & 0x0001) tp->stats.rx_fifo_errors++; - } - } else { - /* Omit the four octet CRC from the length. */ - short pkt_len = ((status >> 16) & 0x7ff) - 4; - struct sk_buff *skb; - -#ifndef final_version - if (pkt_len > 1518) { - printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n", - dev->name, pkt_len, pkt_len); - pkt_len = 1518; - tp->stats.rx_length_errors++; - } -#endif - /* Check if the packet is long enough to accept without copying - to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { - skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align the IP header */ -#if ! defined(__alpha__) - eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0); - skb_put(skb, pkt_len); -#else - memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail, - pkt_len); -#endif - } else { /* Pass up the skb already on the Rx ring. */ - char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len); - tp->rx_skbuff[entry] = NULL; -#ifndef final_version - if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp) - printk(KERN_ERR "%s: Internal fault: The skbuff addresses " - "do not match in tulip_rx: %p vs. %p / %p.\n", - dev->name, - le32desc_to_virt(tp->rx_ring[entry].buffer1), - skb->head, temp); -#endif - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - tp->stats.rx_packets++; - tp->stats.rx_bytes += pkt_len; - } - received++; - entry = (++tp->cur_rx) % RX_RING_SIZE; - } - - return received; -} - - -static void tulip_down (struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *) dev->priv; - - netif_device_detach (dev); - - del_timer (&tp->timer); - - /* Disable interrupts by clearing the interrupt mask. */ - outl (0x00000000, ioaddr + CSR7); - - /* Stop the Tx and Rx processes. */ - outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002); - - /* 21040 -- Leave the card in 10baseT state. */ - if (tp->chip_id == DC21040) - outl (0x00000004, ioaddr + CSR13); - - if (inl (ioaddr + CSR6) != 0xffffffff) - tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff; - - dev->if_port = tp->saved_if_port; - - /* Leave the driver in snooze, not sleep, mode. */ - if (tp->flags & HAS_ACPI) - pci_write_config_dword (tp->pdev, 0x40, 0x40000000); -} - - -static int tulip_close (struct net_device *dev) -{ - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *) dev->priv; - int i; - - tulip_down (dev); - - if (tulip_debug > 1) - printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inl (ioaddr + CSR5)); - - free_irq (dev->irq, dev); - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = tp->rx_skbuff[i]; - tp->rx_skbuff[i] = 0; - tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ - tp->rx_ring[i].length = 0; - tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ - if (skb) { - dev_kfree_skb (skb); - } - } - for (i = 0; i < TX_RING_SIZE; i++) { - if (tp->tx_skbuff[i]) - dev_kfree_skb (tp->tx_skbuff[i]); - tp->tx_skbuff[i] = 0; - } - - MOD_DEC_USE_COUNT; - - return 0; -} - -static struct enet_statistics *tulip_get_stats(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - - if (netif_running(dev)) - tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - - return &tp->stats; -} - - -/* Provide ioctl() calls to examine the MII xcvr state. */ -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - u16 *data = (u16 *)&rq->ifr_data; - int phy = tp->phys[0] & 0x1f; - long flags; - - switch(cmd) { - case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ - if (tp->mii_cnt) - data[0] = phy; - else if (tp->flags & HAS_NWAY143) - data[0] = 32; - else if (tp->chip_id == COMET) - data[0] = 1; - else - return -ENODEV; - case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { - int csr12 = inl(ioaddr + CSR12); - int csr14 = inl(ioaddr + CSR14); - switch (data[1]) { - case 0: { - data[3] = (csr14<<5) & 0x1000; - break; } - case 1: - data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0) - + (csr12&0x06 ? 0x04 : 0); - break; - case 4: { - data[3] = ((csr14>>9)&0x07C0) + - ((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1; - break; - } - case 5: data[3] = csr12 >> 16; break; - default: data[3] = 0; break; - } - } else { - save_flags(flags); - cli(); - data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); - restore_flags(flags); - } - return 0; - case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (data[0] == 32 && (tp->flags & HAS_NWAY143)) { - if (data[1] == 5) - tp->to_advertise = data[2]; - } else { - save_flags(flags); - cli(); - mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); - restore_flags(flags); - } - return 0; - default: - return -EOPNOTSUPP; - } - - return -EOPNOTSUPP; -} - - -/* Set or clear the multicast filter for this adaptor. - Note that we only use exclusion around actually queueing the - new frame, not around filling tp->setup_frame. This is non-deterministic - when re-entered but still correct. */ - -/* The little-endian AUTODIN32 ethernet CRC calculation. - N.B. Do not use for bulk data, use a table-based routine instead. - This is common code and should be moved to net/core/crc.c */ -static unsigned const ethernet_polynomial_le = 0xedb88320U; -static inline u32 ether_crc_le(int length, unsigned char *data) -{ - u32 crc = 0xffffffff; /* Initial value. */ - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 8; --bit >= 0; current_octet >>= 1) { - if ((crc ^ current_octet) & 1) { - crc >>= 1; - crc ^= ethernet_polynomial_le; - } else - crc >>= 1; - } - } - return crc; -} -static unsigned const ethernet_polynomial = 0x04c11db7U; -static inline u32 ether_crc(int length, unsigned char *data) -{ - int crc = -1; - - while(--length >= 0) { - unsigned char current_octet = *data++; - int bit; - for (bit = 0; bit < 8; bit++, current_octet >>= 1) - crc = (crc << 1) ^ - ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); - } - return crc; -} - -static void set_rx_mode(struct net_device *dev) -{ - struct tulip_private *tp = (struct tulip_private *)dev->priv; - long ioaddr = dev->base_addr; - int csr6 = inl(ioaddr + CSR6) & ~0x00D5; - unsigned long cpuflags; - - tp->csr6 &= ~0x00D5; - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - tp->csr6 |= 0x00C0; - csr6 |= 0x00C0; - /* Unconditionally log net taps. */ - printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); - } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { - /* Too many to filter well -- accept all multicasts. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; - } else if (tp->flags & MC_HASH_ONLY) { - /* Some work-alikes have only a 64-entry hash filter table. */ - /* Should verify correctness on big-endian/__powerpc__ */ - struct dev_mc_list *mclist; - int i; - u32 mc_filter[2]; /* Multicast hash filter */ - if (dev->mc_count > 64) { /* Arbitrary non-effective limit. */ - tp->csr6 |= 0x0080; - csr6 |= 0x0080; - } else { - mc_filter[1] = mc_filter[0] = 0; - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter); - if (tp->chip_id == AX88140) { - outl(2, ioaddr + CSR13); - outl(mc_filter[0], ioaddr + CSR14); - outl(3, ioaddr + CSR13); - outl(mc_filter[1], ioaddr + CSR14); - } else if (tp->chip_id == COMET) { /* Has a simple hash filter. */ - outl(mc_filter[0], ioaddr + 0xAC); - outl(mc_filter[1], ioaddr + 0xB0); - } - } - } else { - u16 *eaddrs, *setup_frm = tp->setup_frame; - struct dev_mc_list *mclist; - u32 tx_flags = 0x08000000 | 192; - int i; - - /* Note that only the low-address shortword of setup_frame is valid! - The values are doubled for big-endian architectures. */ - if (dev->mc_count > 14) { /* Must use a multicast hash table. */ - u16 hash_table[32]; - tx_flags = 0x08400000 | 192; /* Use hash filter. */ - memset(hash_table, 0, sizeof(hash_table)); - set_bit(255, hash_table); /* Broadcast entry */ - /* This should work on big-endian machines as well. */ - for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; - i++, mclist = mclist->next) - set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff, - hash_table); - for (i = 0; i < 32; i++) - *setup_frm++ = *setup_frm++ = hash_table[i]; - setup_frm = &tp->setup_frame[13*6]; - } else { - /* We have <= 14 addresses so we can use the wonderful - 16 address perfect filtering of the Tulip. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; - i++, mclist = mclist->next) { - eaddrs = (u16 *)mclist->dmi_addr; - *setup_frm++ = *setup_frm++ = *eaddrs++; - *setup_frm++ = *setup_frm++ = *eaddrs++; - *setup_frm++ = *setup_frm++ = *eaddrs++; - } - /* Fill the unused entries with the broadcast address. */ - memset(setup_frm, 0xff, (15-i)*12); - setup_frm = &tp->setup_frame[15*6]; - } - /* Fill the final entry with our physical address. */ - eaddrs = (u16 *)dev->dev_addr; - *setup_frm++ = *setup_frm++ = eaddrs[0]; - *setup_frm++ = *setup_frm++ = eaddrs[1]; - *setup_frm++ = *setup_frm++ = eaddrs[2]; - /* Now add this frame to the Tx list. */ - spin_lock_irqsave(&tp->tx_lock, cpuflags); - if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { - /* Same setup recently queued, we need not add it. */ - } else { - unsigned long flags; - unsigned int entry; - - save_flags(flags); cli(); - entry = tp->cur_tx++ % TX_RING_SIZE; - - if (entry != 0) { - /* Avoid a chip errata by prefixing a dummy entry. */ - tp->tx_skbuff[entry] = 0; - tp->tx_ring[entry].length = - (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; - tp->tx_ring[entry].buffer1 = 0; - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); - entry = tp->cur_tx++ % TX_RING_SIZE; - } - - tp->tx_skbuff[entry] = 0; - /* Put the setup frame on the Tx list. */ - if (entry == TX_RING_SIZE-1) - tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ - tp->tx_ring[entry].length = cpu_to_le32(tx_flags); - tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame); - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); - if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { - netif_stop_queue(dev); - tp->tx_full = 1; - } - spin_unlock_irqrestore(&tp->tx_lock, cpuflags); - /* Trigger an immediate transmit demand. */ - outl(0, ioaddr + CSR1); - } - } - outl_CSR6(tp, csr6 | 0x0000); -} - - -static int __devinit tulip_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - static int did_version = 0; /* Already printed version info. */ - struct tulip_private *tp; - /* See note below on the multiport cards. */ - static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; - static int last_irq = 0; - static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */ - u8 chip_rev; - int i, irq; - unsigned short sum; - u8 ee_data[EEPROM_SIZE]; - struct net_device *dev; - long ioaddr; - static int board_idx = -1; - int chip_idx = ent->driver_data; - - board_idx++; - - if (tulip_debug > 0 && did_version++ == 0) - printk (KERN_INFO "%s", version); - - if( pdev->subsystem_vendor == 0x1376 ){ - printk (KERN_ERR PFX "skipping LMC card.\n"); - return -ENODEV; - } - - ioaddr = pci_resource_start (pdev, 0); - irq = pdev->irq; - - /* Make certain the data structures are quadword aligned. */ - dev = init_etherdev (NULL, sizeof (*tp)); - if (!dev) { - printk (KERN_ERR PFX "unable to allocate ether device, aborting\n"); - return -ENOMEM; - } - - /* We do a request_region() only to register /proc/ioports info. */ - /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ - if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) { - printk (KERN_ERR PFX "unable to allocate ether device, aborting\n"); - goto err_out_free_netdev; - } - - if (pci_enable_device(pdev)) { - printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, bus %d, devfn %d), aborting\n", - pdev->vendor, pdev->device, - pdev->bus->number, pdev->devfn); - goto err_out_free_netdev; - } - - pci_set_master(pdev); - - tp = dev->priv; - memset(tp, 0, sizeof(*tp)); - - pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); - - printk(KERN_INFO "%s: %s rev %d at %#3lx,", - dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); - - /* Stop the chip's Tx and Rx processes. */ - outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002); - /* Clear the missed-packet counter. */ - (volatile int)inl(ioaddr + CSR8); - - if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { - printk(" 21040 compatible mode,"); - chip_idx = DC21040; - } - - /* The station address ROM is read byte serially. The register must - be polled, waiting for the value to be read bit serially from the - EEPROM. - */ - sum = 0; - if (chip_idx == DC21040) { - outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ - for (i = 0; i < 6; i++) { - int value, boguscnt = 100000; - do - value = inl(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); - dev->dev_addr[i] = value; - sum += value & 0xff; - } - } else if (chip_idx == LC82C168) { - for (i = 0; i < 3; i++) { - int value, boguscnt = 100000; - outl(0x600 | i, ioaddr + 0x98); - do - value = inl(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); - put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); - sum += value & 0xffff; - } - } else if (chip_idx == COMET) { - /* No need to read the EEPROM. */ - put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); - put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); - for (i = 0; i < 6; i ++) - sum += dev->dev_addr[i]; - } else { - /* A serial EEPROM interface, we read now and sort it out later. */ - int sa_offset = 0; - int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; - - for (i = 0; i < sizeof(ee_data)/2; i++) - ((u16 *)ee_data)[i] = - le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size)); - - /* DEC now has a specification (see Notes) but early board makers - just put the address in the first EEPROM locations. */ - /* This does memcmp(eedata, eedata+16, 8) */ - for (i = 0; i < 8; i ++) - if (ee_data[i] != ee_data[16+i]) - sa_offset = 20; - if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { - sa_offset = 2; /* Grrr, damn Matrox boards. */ - multiport_cnt = 4; - } - for (i = 0; i < 6; i ++) { - dev->dev_addr[i] = ee_data[i + sa_offset]; - sum += ee_data[i + sa_offset]; - } - } - /* Lite-On boards have the address byte-swapped. */ - if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0) - && dev->dev_addr[1] == 0x00) - for (i = 0; i < 6; i+=2) { - char tmp = dev->dev_addr[i]; - dev->dev_addr[i] = dev->dev_addr[i+1]; - dev->dev_addr[i+1] = tmp; - } - /* On the Zynx 315 Etherarray and other multiport boards only the - first Tulip has an EEPROM. - The addresses of the subsequent ports are derived from the first. - Many PCI BIOSes also incorrectly report the IRQ line, so we correct - that here as well. */ - if (sum == 0 || sum == 6*0xff) { - printk(" EEPROM not present,"); - for (i = 0; i < 5; i++) - dev->dev_addr[i] = last_phys_addr[i]; - dev->dev_addr[i] = last_phys_addr[i] + 1; -#if defined(__i386__) /* Patch up x86 BIOS bug. */ - if (last_irq) - irq = last_irq; -#endif - } - - for (i = 0; i < 6; i++) - printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]); - printk(", IRQ %d.\n", irq); - last_irq = irq; - - pdev->driver_data = dev; - dev->base_addr = ioaddr; - dev->irq = irq; - - tp->chip_id = chip_idx; - tp->revision = chip_rev; - tp->flags = tulip_tbl[chip_idx].flags; - tp->csr0 = csr0; - tp->pdev = pdev; - tp->base_addr = dev->base_addr; - - /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. - And the ASIX must have a burst limit or horrible things happen. */ - if (chip_idx == DC21143 && chip_rev == 65) - tp->csr0 &= ~0x01000000; - else if (chip_idx == AX88140) - tp->csr0 |= 0x2000; - -#ifdef TULIP_FULL_DUPLEX - tp->full_duplex = 1; - tp->full_duplex_lock = 1; -#endif -#ifdef TULIP_DEFAULT_MEDIA - tp->default_port = TULIP_DEFAULT_MEDIA; -#endif -#ifdef TULIP_NO_MEDIA_SWITCH - tp->medialock = 1; -#endif - tp->tx_lock = SPIN_LOCK_UNLOCKED; - - /* The lower four bits are the media type. */ - if (board_idx >= 0 && board_idx < MAX_UNITS) { - tp->default_port = options[board_idx] & 15; - if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0) - tp->full_duplex = 1; - if (mtu[board_idx] > 0) - dev->mtu = mtu[board_idx]; - } - if (dev->mem_start) - tp->default_port = dev->mem_start; - if (tp->default_port) { - tp->medialock = 1; - if (media_cap[tp->default_port] & MediaAlwaysFD) - tp->full_duplex = 1; - } - if (tp->full_duplex) - tp->full_duplex_lock = 1; - - if (media_cap[tp->default_port] & MediaIsMII) { - u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; - tp->to_advertise = media2advert[tp->default_port - 9]; - } else if (tp->flags & HAS_8023X) - tp->to_advertise = 0x05e1; - else - tp->to_advertise = 0x01e1; - - /* This is logically part of probe1(), but too complex to write inline. */ - if (tp->flags & HAS_MEDIA_TABLE) { - memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); - parse_eeprom(dev); - } - - if ((tp->flags & ALWAYS_CHECK_MII) || - (tp->mtable && tp->mtable->has_mii) || - ( ! tp->mtable && (tp->flags & HAS_MII))) { - int phy, phy_idx; - if (tp->mtable && tp->mtable->has_mii) { - for (i = 0; i < tp->mtable->leafcount; i++) - if (tp->mtable->mleaf[i].media == 11) { - tp->cur_index = i; - tp->saved_if_port = dev->if_port; - select_media(dev, 1); - dev->if_port = tp->saved_if_port; - break; - } - } - /* Find the connected MII xcvrs. - Doing this in open() would allow detecting external xcvrs later, - but takes much time. */ - for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); - phy++) { - int mii_status = mdio_read(dev, phy, 1); - if ((mii_status & 0x8301) == 0x8001 || - ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { - int mii_reg0 = mdio_read(dev, phy, 0); - int mii_advert = mdio_read(dev, phy, 4); - int reg4 = ((mii_status>>6) & tp->to_advertise) | 1; - tp->phys[phy_idx] = phy; - tp->advertising[phy_idx++] = reg4; - printk(KERN_INFO "%s: MII transceiver #%d " - "config %4.4x status %4.4x advertising %4.4x.\n", - dev->name, phy, mii_reg0, mii_status, mii_advert); - /* Fixup for DLink with miswired PHY. */ - if (mii_advert != reg4) { - printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d," - " previously advertising %4.4x.\n", - dev->name, reg4, phy, mii_advert); - printk(KERN_DEBUG "%s: Advertising %4.4x (to advertise" - " is %4.4x).\n", - dev->name, reg4, tp->to_advertise); - mdio_write(dev, phy, 4, reg4); - } - /* Enable autonegotiation: some boards default to off. */ - mdio_write(dev, phy, 0, mii_reg0 | - (tp->full_duplex ? 0x1100 : 0x1000) | - (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); - } - } - tp->mii_cnt = phy_idx; - if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { - printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", - dev->name); - tp->phys[0] = 1; - } - } - - /* The Tulip-specific entries in the device structure. */ - dev->open = tulip_open; - dev->hard_start_xmit = tulip_start_xmit; - dev->tx_timeout = tulip_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - dev->stop = tulip_close; - dev->get_stats = tulip_get_stats; - dev->do_ioctl = private_ioctl; - dev->set_multicast_list = set_rx_mode; - - if ((tp->flags & HAS_NWAY143) || tp->chip_id == DC21041) - tp->link_change = t21142_lnk_change; - else if (tp->flags & HAS_PNICNWAY) - tp->link_change = pnic_lnk_change; - - /* Reset the xcvr interface and turn on heartbeat. */ - switch (chip_idx) { - case DC21041: - tp->to_advertise = 0x0061; - outl(0x00000000, ioaddr + CSR13); - outl(0xFFFFFFFF, ioaddr + CSR14); - outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ - outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200); - outl(0x0000EF05, ioaddr + CSR13); - break; - case DC21040: - outl(0x00000000, ioaddr + CSR13); - outl(0x00000004, ioaddr + CSR13); - break; - case DC21140: default: - if (tp->mtable) - outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); - break; - case DC21142: - case PNIC2: - if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) { - outl_CSR6(tp, 0x82020000); - outl(0x0000, ioaddr + CSR13); - outl(0x0000, ioaddr + CSR14); - outl_CSR6(tp, 0x820E0000); - } else - t21142_start_nway(dev); - break; - case LC82C168: - if ( ! tp->mii_cnt) { - tp->nway = 1; - tp->nwayset = 0; - outl_CSR6(tp, 0x00420000); - outl(0x30, ioaddr + CSR12); - outl_CSR6(tp, 0x0001F078); - outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */ - } - break; - case MX98713: case COMPEX9881: - outl_CSR6(tp, 0x00000000); - outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ - outl(0x00000001, ioaddr + CSR13); - break; - case MX98715: case MX98725: - outl_CSR6(tp, 0x01a80000); - outl(0xFFFFFFFF, ioaddr + CSR14); - outl(0x00001000, ioaddr + CSR12); - break; - case COMET: - /* No initialization necessary. */ - break; - } - - /* put the chip in snooze mode until opened */ - if (tulip_tbl[chip_idx].flags & HAS_ACPI) - pci_write_config_dword(pdev, 0x40, 0x40000000); - - return 0; - -err_out_free_netdev: - unregister_netdev (dev); - kfree (dev); - return -ENODEV; -} - - -static void tulip_suspend (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - if (dev && netif_device_present (dev)) - tulip_down (dev); -} - - -static void tulip_resume (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - if (dev && !netif_device_present (dev)) - tulip_up (dev); -} - - -static void __devexit tulip_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pdev->driver_data; - - if (dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; - unregister_netdev(dev); - release_region(dev->base_addr, - tulip_tbl[tp->chip_id].io_size); - kfree(dev); - } -} - - -static struct pci_driver tulip_driver = { - name: TULIP_MODULE_NAME, - id_table: tulip_pci_tbl, - probe: tulip_init_one, - remove: tulip_remove_one, - suspend: tulip_suspend, - resume: tulip_resume, -}; - - -static int __init tulip_init (void) -{ - return pci_module_init (&tulip_driver); -} - - -static void __exit tulip_cleanup (void) -{ - pci_unregister_driver (&tulip_driver); -} - - -module_init(tulip_init); -module_exit(tulip_cleanup); diff -u --recursive --new-file v2.3.47/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c --- v2.3.47/linux/drivers/net/wan/cosa.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/wan/cosa.c Mon Feb 21 10:23:56 2000 @@ -1,4 +1,4 @@ -/* $Id: cosa.c,v 1.28 1999/10/11 21:06:58 kas Exp $ */ +/* $Id: cosa.c,v 1.30 2000/02/21 15:19:49 kas Exp $ */ /* * Copyright (C) 1995-1997 Jan "Yenya" Kasprzak @@ -222,6 +222,8 @@ #undef DEBUG_IRQS 1 /* Print the message when the IRQ is received */ #undef DEBUG_IO 1 /* Dump the I/O traffic */ +#define TX_TIMEOUT (5*HZ) + /* Maybe the following should be allocated dynamically */ static struct cosa_data cosa_cards[MAX_CARDS]; static int nr_cards = 0; @@ -286,6 +288,7 @@ static void sppp_channel_delete(struct channel_data *chan); static int cosa_sppp_open(struct net_device *d); static int cosa_sppp_close(struct net_device *d); +static void cosa_sppp_timeout(struct net_device *d); static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *d); static char *sppp_setup_rx(struct channel_data *channel, int size); static int sppp_rx_done(struct channel_data *channel); @@ -370,7 +373,7 @@ { int i; - printk(KERN_INFO "cosa v1.06 (c) 1997-8 Jan Kasprzak \n"); + printk(KERN_INFO "cosa v1.07 (c) 1997-2000 Jan Kasprzak \n"); #ifdef __SMP__ printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n"); #endif @@ -406,7 +409,6 @@ #ifdef MODULE void cleanup_module (void) { - int i; struct cosa_data *cosa; printk(KERN_INFO "Unloading the cosa module\n"); @@ -595,6 +597,8 @@ d->hard_start_xmit = cosa_sppp_tx; d->do_ioctl = cosa_sppp_ioctl; d->get_stats = cosa_net_stats; + d->tx_timeout = cosa_sppp_timeout; + d->watchdog_timeo = TX_TIMEOUT; dev_init_buffers(d); if (register_netdev(d) == -1) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); @@ -609,7 +613,6 @@ unregister_netdev(chan->pppdev.dev); } - static int cosa_sppp_open(struct net_device *d) { struct channel_data *chan = d->priv; @@ -646,7 +649,7 @@ return err; } - d->tbusy = 0; + netif_start_queue(d); cosa_enable_rx(chan); return 0; } @@ -655,41 +658,39 @@ { struct channel_data *chan = dev->priv; - if (dev->tbusy) { - if (time_before(jiffies, dev->trans_start+2*HZ)) - return 1; /* Two seconds timeout */ - if (test_bit(RXBIT, &chan->cosa->rxtx)) { - chan->stats.rx_errors++; - chan->stats.rx_missed_errors++; - } else { - chan->stats.tx_errors++; - chan->stats.tx_aborted_errors++; - } - cosa_kick(chan->cosa); - if (chan->tx_skb) { - dev_kfree_skb(chan->tx_skb); - chan->tx_skb = 0; - } - dev->tbusy = 0; - } - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); - return 1; - } - + netif_stop_queue(dev); + chan->tx_skb = skb; - dev->trans_start = jiffies; cosa_start_tx(chan, skb->data, skb->len); return 0; } +static void cosa_sppp_timeout(struct net_device *dev) +{ + struct channel_data *chan = dev->priv; + + if (test_bit(RXBIT, &chan->cosa->rxtx)) { + chan->stats.rx_errors++; + chan->stats.rx_missed_errors++; + } else { + chan->stats.tx_errors++; + chan->stats.tx_aborted_errors++; + } + cosa_kick(chan->cosa); + if (chan->tx_skb) { + dev_kfree_skb(chan->tx_skb); + chan->tx_skb = 0; + } + netif_wake_queue(dev); +} + static int cosa_sppp_close(struct net_device *d) { struct channel_data *chan = d->priv; int flags; + netif_stop_queue(d); sppp_close(d); - d->tbusy = 1; cosa_disable_rx(chan); spin_lock_irqsave(&chan->cosa->lock, flags); if (chan->rx_skb) { @@ -760,8 +761,7 @@ chan->tx_skb = 0; chan->stats.tx_packets++; chan->stats.tx_bytes += size; - chan->pppdev.dev->tbusy = 0; - mark_bh(NET_BH); + netif_wake_queue(chan->pppdev.dev); return 1; } @@ -1350,14 +1350,14 @@ static void cosa_kick(struct cosa_data *cosa) { unsigned flags, flags1; - char *s = "Unknown"; + char *s = "(probably) IRQ"; if (test_bit(RXBIT, &cosa->rxtx)) - s = "RX"; + s = "RX DMA"; if (test_bit(TXBIT, &cosa->rxtx)) - s = "TX"; + s = "TX DMA"; - printk(KERN_INFO "%s: %s DMA timeout - restarting.\n", cosa->name, s); + printk(KERN_INFO "%s: %s timeout - restarting.\n", cosa->name, s); spin_lock_irqsave(&cosa->lock, flags); cosa->rxtx = 0; diff -u --recursive --new-file v2.3.47/linux/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c --- v2.3.47/linux/drivers/net/wan/syncppp.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/net/wan/syncppp.c Tue Feb 22 22:38:31 2000 @@ -50,6 +50,7 @@ #include #include #include +#include #include "syncppp.h" #define MAXALIVECNT 6 /* max. alive packets */ @@ -126,6 +127,7 @@ static struct sppp *spppq; static struct timer_list sppp_keepalive_timer; +static spinlock_t spppq_lock; static void sppp_keepalive (unsigned long dummy); static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, @@ -359,8 +361,8 @@ { struct sppp *sp; unsigned long flags; - save_flags(flags); - cli(); + + spin_lock_irqsave(&spppq_lock, flags); for (sp=spppq; sp; sp=sp->pp_next) { @@ -402,7 +404,7 @@ sp->lcp.echoid, 4, &nmagic); } } - restore_flags(flags); + spin_unlock_irqrestore(&spppq_lock, flags); sppp_keepalive_timer.expires=jiffies+10*HZ; add_timer(&sppp_keepalive_timer); } @@ -915,7 +917,9 @@ { struct net_device *dev = pd->dev; struct sppp *sp = &pd->sppp; - + unsigned long flags; + + spin_lock_irqsave(&spppq_lock, flags); /* Initialize keepalive handler. */ if (! spppq) { @@ -927,6 +931,7 @@ /* Insert new entry into the keepalive list. */ sp->pp_next = spppq; spppq = sp; + spin_unlock_irqrestore(&spppq_lock, flags); sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; @@ -971,7 +976,9 @@ void sppp_detach (struct net_device *dev) { struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev); + unsigned long flags; + spin_lock_irqsave(&spppq_lock, flags); /* Remove the entry from the keepalive list. */ for (q = &spppq; (p = *q); q = &p->pp_next) if (p == sp) { @@ -983,6 +990,7 @@ if (! spppq) del_timer(&sppp_keepalive_timer); sppp_clear_timeout (sp); + spin_unlock_irqrestore(&spppq_lock, flags); } EXPORT_SYMBOL(sppp_detach); @@ -1292,6 +1300,7 @@ { printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"); printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n"); + spin_lock_init(&spppq_lock); sppp_packet_type.type=htons(ETH_P_WAN_PPP); dev_add_pack(&sppp_packet_type); } diff -u --recursive --new-file v2.3.47/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.3.47/linux/drivers/net/wavelan.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/net/wavelan.c Mon Feb 21 20:51:51 2000 @@ -24,24 +24,24 @@ /*------------------------------------------------------------------*/ /* - * Wrapper for disabling interrupts. + * Wrapper for disabling interrupts and locking the driver. + * (note : inline, so optimised away) */ - -static inline unsigned long wv_splhi(void) +static inline void wv_splhi(net_local * lp, + unsigned long * pflags) { - unsigned long flags; - save_flags(flags); - cli(); - return (flags); + spin_lock_irqsave(&lp->spinlock, *pflags); + /* Note : above does the cli(); itself */ } /*------------------------------------------------------------------*/ /* - * Wrapper for re-enabling interrupts. + * Wrapper for re-enabling interrupts and un-locking the driver. */ -static inline void wv_splx(unsigned long flags) +static inline void wv_splx(net_local * lp, + unsigned long * pflags) { - restore_flags(flags); + spin_unlock_irqrestore(&lp->spinlock, *pflags); } /*------------------------------------------------------------------*/ @@ -180,13 +180,12 @@ unsigned long ioaddr = dev->base_addr; unsigned long flags; - save_flags(flags); - cli(); + wv_splhi(lp, &flags); lp->hacr &= ~HACR_INTRON; hacr_write(ioaddr, lp->hacr); - restore_flags(flags); + wv_splx(lp, &flags); } /* wv_ints_off */ /*------------------------------------------------------------------*/ @@ -199,11 +198,12 @@ unsigned long ioaddr = dev->base_addr; unsigned long flags; - save_flags(flags); - cli(); + wv_splhi(lp, &flags); + lp->hacr |= HACR_INTRON; hacr_write(ioaddr, lp->hacr); - restore_flags(flags); + + wv_splx(lp, &flags); } /* wv_ints_on */ /******************* MODEM MANAGEMENT SUBROUTINES *******************/ @@ -707,7 +707,7 @@ printk(KERN_INFO "%s: wv_config_complete(): configure failed; status = 0x%x\n", dev->name, status); -#endif /* DEBUG_CONFIG_ERROR */ +#endif /* DEBUG_CONFIG_ERROR */ ret = 1; /* Ready to be scrapped */ } @@ -723,6 +723,8 @@ /* * Command completion interrupt. * Reclaim as many freed tx buffers as we can. + * (called in wavelan_interrupt()). + * Note : the spinlock is already grabbed for us. */ static int wv_complete(device * dev, unsigned long ioaddr, net_local * lp) { @@ -870,16 +872,20 @@ { net_local *lp = (net_local *) dev->priv; + /* Arm the flag, will be cleard in wv_82586_config() */ + lp->reconfig_82586 = 1; + /* Check if we can do it now ! */ - if (!netif_running(dev) && netif_queue_stopped(dev)) { - lp->reconfig_82586 = 1; + if((netif_running(dev)) && !(netif_queue_stopped(dev))) + /* May fail */ + wv_82586_config(dev); + else { #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "%s: wv_82586_reconfig(): delayed (state = %lX)\n", dev->name, dev->state); #endif - } else - wv_82586_config(dev); + } } /********************* DEBUG & INFO SUBROUTINES *********************/ @@ -1806,9 +1812,9 @@ #endif /* Disable interrupts and save flags. */ - save_flags(flags); - cli(); + wv_splhi(lp, &flags); /* FIXME: can't copy*user when cli this is broken! */ + /* Note : is it still valid ? Jean II */ /* Look what is the request */ switch (cmd) { @@ -2271,7 +2277,7 @@ } /* Enable interrupts and restore flags. */ - restore_flags(flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); @@ -2297,15 +2303,12 @@ dev->name); #endif - /* Disable interrupts and save flags. */ - save_flags(flags); - cli(); - + /* Check */ if (lp == (net_local *) NULL) - { - restore_flags(flags); return (iw_stats *) NULL; - } + + /* Disable interrupts and save flags. */ + wv_splhi(lp, &flags); wstats = &lp->wstats; @@ -2333,7 +2336,7 @@ wstats->discard.misc = 0L; /* Enable interrupts and restore flags. */ - restore_flags(flags); + wv_splx(lp, &flags); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", @@ -2455,7 +2458,8 @@ /* * Transfer as many packets as we can * from the device RAM. - * Called by the interrupt handler. + * (called in wavelan_interrupt()). + * Note : the spinlock is already grabbed for us. */ static inline void wv_receive(device * dev) { @@ -2640,7 +2644,7 @@ * * (called in wavelan_packet_xmit()) */ -static inline void wv_packet_write(device * dev, void *buf, short length) +static inline int wv_packet_write(device * dev, void *buf, short length) { net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; @@ -2665,9 +2669,18 @@ if (clen < ETH_ZLEN) clen = ETH_ZLEN; - save_flags(flags); - cli(); - + wv_splhi(lp, &flags); + + /* Check nothing bad has happened */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { +#ifdef DEBUG_TX_ERROR + printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", + dev->name); +#endif + wv_splx(lp, &flags); + return 1; + } + /* Calculate addresses of next block and previous block. */ txblock = lp->tx_first_free; txpred = txblock - TXBLOCKZ; @@ -2736,20 +2749,13 @@ /* Keep stats up to date. */ lp->stats.tx_bytes += length; - /* If watchdog not already active, activate it... */ - if (lp->watchdog.prev == (timer_list *) NULL) { - /* Set timer to expire in WATCHDOG_JIFFIES. */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - if (lp->tx_first_in_use == I82586NULL) lp->tx_first_in_use = txblock; if (lp->tx_n_in_use < NTXBLOCKS - 1) netif_wake_queue(dev); - restore_flags(flags); + wv_splx(lp, &flags); #ifdef DEBUG_TX_INFO wv_packet_info((u8 *) buf, length, dev->name, @@ -2759,6 +2765,8 @@ #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); #endif + + return 0; } /*------------------------------------------------------------------*/ @@ -2781,7 +2789,6 @@ * Block a timer-based transmit from overlapping. * In other words, prevent reentering this routine. */ - netif_stop_queue(dev); /* If somebody has asked to reconfigure the controller, @@ -2789,13 +2796,18 @@ */ if (lp->reconfig_82586) { wv_82586_config(dev); + /* Check that we can continue */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) + return 1; } #ifdef DEBUG_TX_ERROR if (skb->next) printk(KERN_INFO "skb has next\n"); #endif - wv_packet_write(dev, skb->data, skb->len); + /* Write packet on the card */ + if(wv_packet_write(dev, skb->data, skb->len)) + return 1; /* We failed */ dev_kfree_skb(skb); @@ -3161,7 +3173,7 @@ } lp->tx_n_in_use = 0; - netif_wake_queue(dev); + netif_start_queue(dev); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); #endif @@ -3310,7 +3322,7 @@ * as usual to the NOP command. * Note that only the last command (mc_set) will generate an interrupt. * - * (called by wv_hw_reset(), wv_82586_reconfig()) + * (called by wv_hw_reset(), wv_82586_reconfig(), wavelan_packet_xmit()) */ static void wv_82586_config(device * dev) { @@ -3336,9 +3348,18 @@ printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); #endif - save_flags(flags); - cli(); + wv_splhi(lp, &flags); + /* Check nothing bad has happened */ + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { +#ifdef DEBUG_CONFIG_ERROR + printk(KERN_INFO "%s: wv_82586_config(): Tx queue full.\n", + dev->name); +#endif + wv_splx(lp, &flags); + return; + } + /* Calculate addresses of next block and previous block. */ txblock = lp->tx_first_free; txpred = txblock - TXBLOCKZ; @@ -3467,22 +3488,17 @@ (unsigned char *) &nop.nop_h.ac_link, sizeof(nop.nop_h.ac_link)); - /* If watchdog not already active, activate it... */ - if (lp->watchdog.prev == (timer_list *) NULL) { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } - + /* Job done, clear the flag */ lp->reconfig_82586 = 0; if (lp->tx_first_in_use == I82586NULL) lp->tx_first_in_use = txblock; - if (lp->tx_n_in_use < NTXBLOCKS - 1) - netif_wake_queue(dev); + if (lp->tx_n_in_use == (NTXBLOCKS - 1)) + netif_stop_queue(dev); + + wv_splx(lp, &flags); - restore_flags(flags); #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); #endif @@ -3539,10 +3555,6 @@ (unsigned int) dev); #endif - /* If watchdog was activated, kill it! */ - if (lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); - /* Increase the number of resets done. */ lp->nresets++; @@ -3637,8 +3649,19 @@ lp = (net_local *) dev->priv; ioaddr = dev->base_addr; - /* Prevent reentrance. What should we do here? */ +#ifdef DEBUG_INTERRUPT_ERROR + /* Check state of our spinlock (it should be cleared) */ + if(spin_is_locked(&lp->spinlock)) + printk(KERN_INFO + "%s: wavelan_interrupt(): spinlock is already locked !!!\n", + dev->name); +#endif + + /* Prevent reentrancy. It is safe because wv_splhi disable interrupts + * before aquiring the spinlock */ + spin_lock(&lp->spinlock); + /* Check modem interupt */ if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) { u8 dce_status; @@ -3655,6 +3678,7 @@ #endif } + /* Check if not controller interrupt */ if ((hasr & HASR_82586_INTR) == 0) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO @@ -3689,15 +3713,6 @@ dev->name); #endif wv_complete(dev, ioaddr, lp); - - /* If watchdog was activated, kill it ! */ - if (lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); - if (lp->tx_n_in_use > 0) { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); - } } /* Frame received. */ @@ -3710,9 +3725,13 @@ wv_receive(dev); } + /* Release spinlock here so that wv_hw_reset() can grab it */ + spin_unlock (&lp->lock); + /* Check the state of the command unit. */ if (((status & SCB_ST_CNA) == SCB_ST_CNA) || - (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && netif_running(dev))) { + (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && + (netif_running(dev)))) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wavelan_interrupt(): CU inactive -- restarting\n", @@ -3723,7 +3742,8 @@ /* Check the state of the command unit. */ if (((status & SCB_ST_RNR) == SCB_ST_RNR) || - (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && netif_running(dev))) { + (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && + (netif_running(dev)))) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wavelan_interrupt(): RU not ready -- restarting\n", @@ -3739,26 +3759,16 @@ /*------------------------------------------------------------------*/ /* - * Watchdog: when we start a transmission, we set a timer in the + * Watchdog: when we start a transmission, a timer is set for us in the * kernel. If the transmission completes, this timer is disabled. If - * the timer expires, we try to unlock the hardware. - * - * Note: this watchdog doesn't work on the same principle as the - * watchdog in the previous version of the ISA driver. I made it this - * way because the overhead of add_timer() and del_timer() is nothing - * and because it avoids calling the watchdog, saving some CPU. + * the timer expires, we are called and we try to unlock the hardware. */ -static void wavelan_watchdog(unsigned long a) +static void wavelan_watchdog(device * dev) { - device *dev; - net_local *lp; - unsigned long ioaddr; - unsigned long flags; - unsigned int nreaped; - - dev = (device *) a; - ioaddr = dev->base_addr; - lp = (net_local *) dev->priv; + net_local * lp = (net_local *)dev->priv; + u_long ioaddr = dev->base_addr; + unsigned long flags; + unsigned int nreaped; #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); @@ -3769,18 +3779,16 @@ dev->name); #endif - save_flags(flags); - cli(); - - dev = (device *) a; - ioaddr = dev->base_addr; - lp = (net_local *) dev->priv; + wv_splhi(lp, &flags); + /* Check that we came here for something */ if (lp->tx_n_in_use <= 0) { - restore_flags(flags); + wv_splx(lp, &flags); return; } + /* Try to see if some buffers are not free (in case we missed + * an interrupt */ nreaped = wv_complete(dev, ioaddr, lp); #ifdef DEBUG_INTERRUPT_INFO @@ -3811,15 +3819,13 @@ dev->name); #endif wv_hw_reset(dev); - } else - /* Reset watchdog for next transmission. */ - if (lp->tx_n_in_use > 0) { - /* set timer to expire in WATCHDOG_JIFFIES */ - lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; - add_timer(&lp->watchdog); } - restore_flags(flags); + /* At this point, we should have some free Tx buffer ;-) */ + if (lp->tx_n_in_use < NTXBLOCKS - 1) + netif_wake_queue(dev); + + wv_splx(lp, &flags); #ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); @@ -3840,7 +3846,8 @@ */ static int wavelan_open(device * dev) { - unsigned long flags; + net_local * lp = (net_local *)dev->priv; + unsigned long flags; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, @@ -3865,8 +3872,7 @@ return -EAGAIN; } - save_flags(flags); - cli(); + wv_splhi(lp, &flags); if (wv_hw_reset(dev) != -1) { netif_start_queue(dev); @@ -3879,7 +3885,7 @@ #endif return -EAGAIN; } - restore_flags(flags); + wv_splx(lp, &flags); MOD_INC_USE_COUNT; @@ -3896,8 +3902,6 @@ */ static int wavelan_close(device * dev) { - net_local *lp = (net_local *) dev->priv; - #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, (unsigned int) dev); @@ -3905,10 +3909,6 @@ netif_stop_queue(dev); - /* If watchdog was activated, kill it! */ - if (lp->watchdog.prev != (timer_list *) NULL) - del_timer(&lp->watchdog); - /* * Flush the Tx and disable Rx. */ @@ -4001,11 +4001,13 @@ lp->hacr = HACR_DEFAULT; - lp->watchdog.function = wavelan_watchdog; - lp->watchdog.data = (unsigned long) dev; + /* Multicast stuff */ lp->promiscuous = 0; lp->mc_count = 0; + /* Init spinlock */ + spin_lock_init(&lp->lock); + /* * Fill in the fields of the device structure * with generic Ethernet values. @@ -4017,6 +4019,8 @@ dev->hard_start_xmit = wavelan_packet_xmit; dev->get_stats = wavelan_get_stats; dev->set_multicast_list = &wavelan_set_multicast_list; + dev->tx_timeout = &wavelan_watchdog; + dev->watchdog_timeo = WATCHDOG_JIFFIES; #ifdef SET_MAC_ADDRESS dev->set_mac_address = &wavelan_set_mac_address; #endif /* SET_MAC_ADDRESS */ diff -u --recursive --new-file v2.3.47/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h --- v2.3.47/linux/drivers/net/wavelan.p.h Tue Dec 7 09:32:44 1999 +++ linux/drivers/net/wavelan.p.h Mon Feb 21 20:51:51 2000 @@ -34,6 +34,25 @@ * I try to maintain a web page with the Wireless LAN Howto at : * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html * + * SMP + * --- + * We now *should* be SMP compliant. + * I don't have a SMP box to verify that (my Pentium 90 is not), so + * someone has to certify that from me. + * Anyway, I spent enough time chasing interrupt re-entrancy during + * errors or reconfigure, and I designed the locked/unlocked sections + * of the driver with great care, and with the recent addition of + * the spinlock (thanks to the new API), we should be quite close to + * the truth. + * The SMP/IRQ locking is quite coarse and conservative (i.e. not fast), + * but better safe than sorry (especially at 2 Mb/s ;-). + * + * I have also looked into disabling only our interrupt on the card + * (via HACR) instead of all interrupts in the processor (via cli), + * so that other driver are not impacted, and it look like it's + * possible, but it's very tricky to do right (full of races). As + * the gain would be mostly for SMP systems, it can wait... + * * Debugging and options * --------------------- * You will find below a set of '#define" allowing a very fine control @@ -171,7 +190,7 @@ * * Thanks go also to: * James Ashton , - * Alan Cox , + * Alan Cox , * Allan Creighton , * Matthew Geier , * Remo di Giovanni , @@ -188,8 +207,9 @@ * * Additional Credits: * - * My development has been done under Linux 2.0.x (Debian 1.1) with - * an HP Vectra XP/60. + * My development has been done initially under Debian 1.1 (Linux 2.0.x) + * and now under Debian 2.2, initially with an HP Vectra XP/60, and now + * an HP Vectra XP/90. * */ @@ -305,6 +325,21 @@ * - Fix check for root permission (break instead of exit) * - New nwid & encoding setting (Wireless Extension 9) * + * Changes made for release in 2.3.49 : + * ---------------------------------- + * - Indentation reformating (Alan) + * - Update to new network API (softnet - 2.3.43) : + * o replace dev->tbusy (Alan) + * o replace dev->tstart (Alan) + * o remove dev->interrupt (Alan) + * o add SMP locking via spinlock in splxx (me) + * o add spinlock in interrupt handler (me) + * o use kernel watchdog instead of ours (me) + * o increase watchdog timeout (kernel is more sensitive) (me) + * o verify that all the changes make sense and work (me) + * - Fixup a potential gotcha when reconfiguring and thighten a bit + * the interactions with Tx queue. + * * Wishes & dreams: * ---------------- * - roaming (see Pcmcia driver) @@ -395,11 +430,11 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v21 (wireless extensions) 16/10/99\n"; +static const char *version = "wavelan.c : v22 (wireless extensions) 21/02/00\n"; #endif /* Watchdog temporisation */ -#define WATCHDOG_JIFFIES (256*HZ/100) +#define WATCHDOG_JIFFIES (512*HZ/100) /* Macro to get the number of elements in an array */ #define NELS(a) (sizeof(a) / sizeof(a[0])) @@ -441,12 +476,12 @@ { net_local * next; /* linked list of the devices */ device * dev; /* reverse link */ + spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ en_stats stats; /* Ethernet interface statistics */ int nresets; /* number of hardware resets */ u_char reconfig_82586; /* We need to reconfigure the controller. */ u_char promiscuous; /* promiscuous mode */ int mc_count; /* number of multicast addresses */ - timer_list watchdog; /* to avoid blocking state */ u_short hacr; /* current host interface state */ int tx_n_in_use; @@ -475,10 +510,12 @@ /**************************** PROTOTYPES ****************************/ /* ----------------------- MISC. SUBROUTINES ------------------------ */ -static inline unsigned long /* flags */ - wv_splhi(void); /* Disable interrupts */ static inline void - wv_splx(unsigned long); /* Enable interrupts: flags */ + wv_splhi(net_local *, /* Disable interrupts, lock driver */ + unsigned long *); /* flags */ +static inline void + wv_splx(net_local *, /* Enable interrupts, unlock driver */ + unsigned long *); /* flags */ static u_char wv_irq_to_psa(int); static int @@ -580,7 +617,7 @@ int), wv_receive(device *); /* Read all packets waiting. */ /* --------------------- PACKET TRANSMISSION --------------------- */ -static inline void +static inline int wv_packet_write(device *, /* Write a packet to the Tx buffer. */ void *, short); @@ -607,7 +644,7 @@ void *, struct pt_regs *); static void - wavelan_watchdog(u_long); /* transmission watchdog */ + wavelan_watchdog(device *); /* transmission watchdog */ /* ------------------- CONFIGURATION CALLBACKS ------------------- */ static int wavelan_open(device *), /* Open the device. */ diff -u --recursive --new-file v2.3.47/linux/drivers/parport/daisy.c linux/drivers/parport/daisy.c --- v2.3.47/linux/drivers/parport/daisy.c Sat Jul 3 10:45:04 1999 +++ linux/drivers/parport/daisy.c Tue Feb 22 22:42:16 2000 @@ -1,7 +1,7 @@ /* * IEEE 1284.3 Parallel port daisy chain and multiplexor code * - * Copyright (C) 1999 Tim Waugh + * Copyright (C) 1999, 2000 Tim Waugh * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,6 +12,7 @@ * 31-01-1999: Make port-cloning transparent. * 13-02-1999: Move DeviceID technique from parport_probe. * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too. + * 22-02-2000: Count devices that are actually detected. * */ @@ -80,9 +81,11 @@ return extra; } -/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */ +/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. + * Return value is number of devices actually detected. */ int parport_daisy_init (struct parport *port) { + int detected = 0; char *deviceid; static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" }; int num_ports; @@ -128,7 +131,7 @@ select_port (port); parport_daisy_deselect_all (port); - assign_addrs (port); + detected += assign_addrs (port); /* Count the potential legacy device at the end. */ add_dev (numdevs++, port, -1); @@ -136,25 +139,31 @@ /* Find out the legacy device's IEEE 1284 device ID. */ deviceid = kmalloc (1000, GFP_KERNEL); if (deviceid) { - parport_device_id (numdevs - 1, deviceid, 1000); + if (parport_device_id (numdevs - 1, deviceid, 1000) > 2) + detected++; + kfree (deviceid); } - return 0; + return detected; } /* Forget about devices on a physical port. */ void parport_daisy_fini (struct parport *port) { struct daisydev *dev, *prev = topology; - while (prev && prev->port == port) - prev = topology = topology->next; + while (prev && prev->port == port) { + topology = topology->next; + kfree (prev); + prev = topology; + } while (prev) { dev = prev->next; if (dev && dev->port == port) prev->next = dev->next; + kfree (dev); prev = prev->next; } @@ -162,7 +171,8 @@ someone enumerate through all IEEE1284.3 devices in the topology?. */ if (!topology) numdevs = 0; - return; } + return; +} /* Find a device by canonical device number. */ struct pardevice *parport_open (int devnum, const char *name, @@ -371,7 +381,7 @@ | PARPORT_STATUS_ERROR)) { DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n", port->name, s); - return -ENXIO; + return 0; } parport_write_data (port, 0x87); udelay (2); @@ -382,7 +392,7 @@ if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) { DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n", port->name, s); - return -ENXIO; + return 0; } parport_write_data (port, 0x78); udelay (2); @@ -421,7 +431,7 @@ parport_device_id (thisdev, deviceid, 1000); kfree (deviceid); - return 0; + return numdevs - thisdev; } /* Find a device with a particular manufacturer and model string, diff -u --recursive --new-file v2.3.47/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.3.47/linux/drivers/parport/parport_pc.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/parport/parport_pc.c Sat Feb 26 20:34:34 2000 @@ -681,6 +681,7 @@ /* Set up parallel port FIFO mode.*/ parport_pc_data_forward (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0); change_mode (port, ECR_PPF); /* Parallel port FIFO */ port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; @@ -747,6 +748,10 @@ /* Set up ECP parallel port mode.*/ parport_pc_data_forward (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD, + 0); change_mode (port, ECR_ECP); /* ECP FIFO */ port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; @@ -850,6 +855,10 @@ /* Set up ECP parallel port mode.*/ parport_pc_data_reverse (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD, + 0); change_mode (port, ECR_ECP); /* ECP FIFO */ port->ieee1284.phase = IEEE1284_PH_REV_DATA; @@ -989,7 +998,7 @@ /* * Checks for port existence, all ports support SPP MODE */ -static int __maybe_init parport_SPP_supported(struct parport *pb) +static int __devinit parport_SPP_supported(struct parport *pb) { unsigned char r, w; @@ -1066,7 +1075,7 @@ * two bits of ECR aren't writable, so we check by writing ECR and * reading it back to see if it's what we expect. */ -static int __maybe_init parport_ECR_present(struct parport *pb) +static int __devinit parport_ECR_present(struct parport *pb) { struct parport_pc_private *priv = pb->private_data; unsigned char r = 0xc; @@ -1118,7 +1127,7 @@ * be misdetected here is rather academic. */ -static int __maybe_init parport_PS2_supported(struct parport *pb) +static int __devinit parport_PS2_supported(struct parport *pb) { int ok = 0; @@ -1146,7 +1155,7 @@ return ok; } -static int __maybe_init parport_ECP_supported(struct parport *pb) +static int __devinit parport_ECP_supported(struct parport *pb) { int i; int config; @@ -1257,7 +1266,7 @@ return 1; } -static int __maybe_init parport_ECPPS2_supported(struct parport *pb) +static int __devinit parport_ECPPS2_supported(struct parport *pb) { const struct parport_pc_private *priv = pb->private_data; int result; @@ -1277,7 +1286,7 @@ /* EPP mode detection */ -static int __maybe_init parport_EPP_supported(struct parport *pb) +static int __devinit parport_EPP_supported(struct parport *pb) { const struct parport_pc_private *priv = pb->private_data; @@ -1320,7 +1329,7 @@ return 1; } -static int __maybe_init parport_ECPEPP_supported(struct parport *pb) +static int __devinit parport_ECPEPP_supported(struct parport *pb) { struct parport_pc_private *priv = pb->private_data; int result; @@ -1351,18 +1360,18 @@ #else /* No IEEE 1284 support */ /* Don't bother probing for modes we know we won't use. */ -static int __maybe_init parport_PS2_supported(struct parport *pb) { return 0; } -static int __maybe_init parport_ECP_supported(struct parport *pb) { return 0; } -static int __maybe_init parport_EPP_supported(struct parport *pb) { return 0; } -static int __maybe_init parport_ECPEPP_supported(struct parport *pb){return 0;} -static int __maybe_init parport_ECPPS2_supported(struct parport *pb){return 0;} +static int __devinit parport_PS2_supported(struct parport *pb) { return 0; } +static int __devinit parport_ECP_supported(struct parport *pb) { return 0; } +static int __devinit parport_EPP_supported(struct parport *pb) { return 0; } +static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;} +static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;} #endif /* No IEEE 1284 support */ /* --- IRQ detection -------------------------------------- */ /* Only if supports ECP mode */ -static int __maybe_init programmable_irq_support(struct parport *pb) +static int __devinit programmable_irq_support(struct parport *pb) { int irq, intrLine; unsigned char oecr = inb (ECONTROL (pb)); @@ -1379,7 +1388,7 @@ return irq; } -static int __maybe_init irq_probe_ECP(struct parport *pb) +static int __devinit irq_probe_ECP(struct parport *pb) { int i; unsigned long irqs; @@ -1408,7 +1417,7 @@ * This detection seems that only works in National Semiconductors * This doesn't work in SMC, LGS, and Winbond */ -static int __maybe_init irq_probe_EPP(struct parport *pb) +static int __devinit irq_probe_EPP(struct parport *pb) { #ifndef ADVANCED_DETECT return PARPORT_IRQ_NONE; @@ -1448,7 +1457,7 @@ #endif /* Advanced detection */ } -static int __maybe_init irq_probe_SPP(struct parport *pb) +static int __devinit irq_probe_SPP(struct parport *pb) { /* Don't even try to do this. */ return PARPORT_IRQ_NONE; @@ -1461,7 +1470,7 @@ * When ECP is available we can autoprobe for IRQs. * NOTE: If we can autoprobe it, we can register the IRQ. */ -static int __maybe_init parport_irq_probe(struct parport *pb) +static int __devinit parport_irq_probe(struct parport *pb) { const struct parport_pc_private *priv = pb->private_data; @@ -1495,7 +1504,7 @@ /* --- DMA detection -------------------------------------- */ /* Only if supports ECP mode */ -static int __maybe_init programmable_dma_support (struct parport *p) +static int __devinit programmable_dma_support (struct parport *p) { unsigned char oecr = inb (ECONTROL (p)); int dma; @@ -1510,7 +1519,7 @@ return dma; } -static int __maybe_init parport_dma_probe (struct parport *p) +static int __devinit parport_dma_probe (struct parport *p) { const struct parport_pc_private *priv = p->private_data; if (priv->ecr) @@ -1521,7 +1530,7 @@ /* --- Initialisation code -------------------------------- */ -struct parport *__maybe_init parport_pc_probe_port (unsigned long int base, +struct parport *__devinit parport_pc_probe_port (unsigned long int base, unsigned long int base_hi, int irq, int dma, struct pci_dev *dev) @@ -1693,9 +1702,7 @@ #endif /* CONFIG_PARPORT_PC_FIFO */ } - /* Done probing. Now put the port into a sensible start-up state. - * SELECT | INIT also puts IEEE1284-compliant devices into - * compatibility mode. */ + /* Done probing. Now put the port into a sensible start-up state. */ if (priv->ecr) /* * Put the ECP detected port in PS2 mode. @@ -1714,9 +1721,143 @@ return p; } + +static int __devinit sio_via_686a_probe (struct pci_dev *pdev) +{ + u8 dma, irq, tmp; + unsigned port1, port2, have_eppecp; + + /* + * unlock super i/o configuration, set 0x85_1 + */ + pci_read_config_byte (pdev, 0x85, &tmp); + tmp |= (1 << 1); + pci_write_config_byte (pdev, 0x85, tmp); + + /* + * Super I/O configuration, index port == 3f0h, data port == 3f1h + */ + + /* 0xE2_1-0: Parallel Port Mode / Enable */ + outb (0xE2, 0x3F0); + tmp = inb (0x3F1); + + if ((tmp & 0x03) == 0x03) { + printk (KERN_INFO "parport_pc: Via 686A parallel port disabled in BIOS\n"); + return 0; + } + + /* 0xE6: Parallel Port I/O Base Address, bits 9-2 */ + outb (0xE6, 0x3F0); + port1 = inb (0x3F1) << 2; + + switch (port1) { + case 0x3bc: port2 = 0x7bc; break; + case 0x378: port2 = 0x778; break; + case 0x278: port2 = 0x678; break; + default: + printk (KERN_INFO "parport_pc: Via 686A weird parport base 0x%X, ignoring\n", + port1); + return 0; + } + + /* 0xF0_5: EPP+ECP enable */ + outb (0xF0, 0x3F0); + have_eppecp = (inb (0x3F1) & (1 << 5)); + + /* + * lock super i/o configuration, clear 0x85_1 + */ + pci_read_config_byte (pdev, 0x85, &tmp); + tmp &= ~(1 << 1); + pci_write_config_byte (pdev, 0x85, tmp); + + /* + * Get DMA and IRQ from PCI->ISA bridge PCI config registers + */ + + /* 0x50_3-2: PnP Routing for Parallel Port DRQ */ + pci_read_config_byte (pdev, 0x50, &dma); + dma = ((dma >> 2) & 0x03); + + /* 0x51_7-4: PnP Routing for Parallel Port IRQ */ + pci_read_config_byte (pdev, 0x51, &irq); + irq = ((irq >> 4) & 0x0F); + + /* filter bogus IRQs */ + switch (irq) { + case 0: + case 2: + case 8: + case 13: + irq = PARPORT_IRQ_NONE; + break; + + default: /* do nothing */ + break; + } + + /* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */ + if (!have_eppecp) + dma = PARPORT_DMA_NONE; + + /* finally, do the probe with values obtained */ + if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) { + printk (KERN_INFO "parport_pc: Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n", + port1, irq, dma); + return 1; + } + + printk (KERN_WARNING "parport_pc: Strange, can't probe Via 686A parallel port: io=0x%X, irq=%d, dma=%d\n", + port1, irq, dma); + return 0; +} + + +enum parport_pc_sio_types { + sio_via_686a = 0, /* Via VT82C686A motherboard Super I/O */ +}; + + +/* each element directly indexed from enum list, above */ +static struct parport_pc_superio { + int (*probe) (struct pci_dev *pdev); +} parport_pc_superio_info[] __devinitdata = { + { sio_via_686a_probe, }, +}; + + +static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = { + { 0x1106, 0x0686, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_686a }, + { 0, }, /* terminate list */ +}; + + +static int __devinit parport_pc_init_superio(void) +{ + const struct pci_device_id *id; + struct pci_dev *pdev; + + pci_for_each_dev(pdev) { + id = pci_match_device (parport_pc_pci_tbl, pdev); + if (id == NULL) + continue; + + return parport_pc_superio_info[id->driver_data].probe (pdev); + } + + return 0; /* zero devices found */ +} + + /* Look for PCI parallel port cards. */ static int __init parport_pc_init_pci (int irq, int dma) { +#ifndef PCI_VENDOR_ID_AFAVLAB +#define PCI_VENDOR_ID_AFAVLAB 0x14db +#define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120 +#endif + struct { unsigned int vendor; unsigned int device; @@ -1800,6 +1941,9 @@ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 2, { { 4, -1 }, { 5, -1 }, } }, + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902, + PCI_ANY_ID, PCI_ANY_ID, + 1, { { 0, 1 }, } }, { 0, } }; diff -u --recursive --new-file v2.3.47/linux/drivers/parport/probe.c linux/drivers/parport/probe.c --- v2.3.47/linux/drivers/parport/probe.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/parport/probe.c Thu Feb 24 10:08:32 2000 @@ -150,13 +150,11 @@ if (!retval) { int idlen; unsigned char length[2]; - mm_segment_t oldfs = get_fs (); - set_fs (get_ds ()); /* First two bytes are MSB,LSB of inclusive length. */ retval = parport_read (dev->port, length, 2); - if (retval != 2) goto restore_fs; + if (retval != 2) goto end_id; idlen = (length[0] << 8) + length[1] - 2; if (idlen < len) @@ -169,8 +167,8 @@ len); /* Some printer manufacturers mistakenly believe that - the length field is supposed to be _exclusive_. */ - /* In addition, there are broken devices out there + the length field is supposed to be _exclusive_. + In addition, there are broken devices out there that don't even finish off with a semi-colon. */ if (buffer[len - 1] != ';') { ssize_t diff; @@ -196,9 +194,8 @@ } } - restore_fs: + end_id: buffer[len] = '\0'; - set_fs (oldfs); parport_negotiate (dev->port, IEEE1284_MODE_COMPAT); } parport_release (dev); diff -u --recursive --new-file v2.3.47/linux/drivers/parport/share.c linux/drivers/parport/share.c --- v2.3.47/linux/drivers/parport/share.c Tue Jan 4 13:57:17 2000 +++ linux/drivers/parport/share.c Tue Feb 22 22:42:16 2000 @@ -247,7 +247,19 @@ { #ifdef CONFIG_PARPORT_1284 /* Analyse the IEEE1284.3 topology of the port. */ - parport_daisy_init (port); + if (parport_daisy_init (port) == 0) { + /* No devices were detected. Perhaps they are in some + funny state; let's try to reset them and see if + they wake up. */ + parport_daisy_fini (port); + parport_write_control (port, PARPORT_CONTROL_SELECT); + udelay (50); + parport_write_control (port, + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_INIT); + udelay (50); + parport_daisy_init (port); + } #endif /* Let drivers know that a new port has arrived. */ diff -u --recursive --new-file v2.3.47/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids --- v2.3.47/linux/drivers/pci/pci.ids Thu Feb 10 17:11:12 2000 +++ linux/drivers/pci/pci.ids Sat Feb 26 20:32:14 2000 @@ -999,7 +999,7 @@ 10a7 Benchmarq Microelectronics 10a8 Sierra Semiconductor 0000 STB Horizon 64 -10a9 Silicon Graphics +10a9 Silicon Graphics, Inc. 0003 IOC3 0005 RAD Audio 0009 Alteon Gigabit Ethernet @@ -2682,6 +2682,7 @@ 13c0 Microgate Corporation 0010 SyncLink WAN Adapter 13c1 3ware Inc + 1000 3ware ATA-RAID 13c2 Technotrend Systemtechnik GmbH 13c3 Janz Computer AG 13c4 Phase Metrics @@ -3424,6 +3425,7 @@ 71a0 440GX - 82443GX Host bridge 71a1 440GX - 82443GX AGP bridge 71a2 440GX - 82443GX Host bridge (AGP disabled) + 7601 82372FB PIIX4 IDE 7602 82372FB [PCI-to-USB UHCI] 7800 i740 1092 0100 Stealth II G460 diff -u --recursive --new-file v2.3.47/linux/drivers/pci/proc.c linux/drivers/pci/proc.c --- v2.3.47/linux/drivers/pci/proc.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/pci/proc.c Sat Feb 26 20:33:03 2000 @@ -197,10 +197,6 @@ write: proc_bus_pci_write, }; -static struct inode_operations proc_bus_pci_inode_operations = { - &proc_bus_pci_operations, /* default base directory file-ops */ -}; - #if BITS_PER_LONG == 32 #define LONG_FORMAT "\t%08lx" #else @@ -265,7 +261,7 @@ e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de); if (!e) return -ENOMEM; - e->ops = &proc_bus_pci_inode_operations; + e->proc_fops = &proc_bus_pci_operations; e->data = dev; e->size = PCI_CFG_SPACE_SIZE; return 0; diff -u --recursive --new-file v2.3.47/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c --- v2.3.47/linux/drivers/pcmcia/i82365.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/pcmcia/i82365.c Mon Feb 21 21:30:55 2000 @@ -165,25 +165,6 @@ u_char ctl, ema; } vg46x_state_t; -typedef struct ti113x_state_t { - u_int sysctl; - u_char cardctl, devctl, diag; -} ti113x_state_t; - -typedef struct rl5c4xx_state_t { - u_short misc, ctl, io, mem; -} rl5c4xx_state_t; - -typedef struct o2micro_state_t { - u_char mode_a, mode_b, mode_c, mode_d; - u_char mhpg, fifo, mode_e; -} o2micro_state_t; - -typedef struct topic_state_t { - u_char slot, ccr, cdr; - u_int rcr; -} topic_state_t; - typedef struct socket_info_t { u_short type, flags; socket_cap_t cap; @@ -273,22 +254,6 @@ }; #define PCIC_COUNT (sizeof(pcic)/sizeof(pcic_t)) - -/*====================================================================*/ - -/* Some PCI shortcuts */ - -#define config_readb(sock, r, v) pci_read_config_byte((sock)->pdev, r, v) -#define config_readw(sock, r, v) pci_read_config_word((sock)->pdev, r, v) -#define config_readl(sock, r, v) pci_read_config_dword((sock)->pdev, r, v) -#define config_writeb(sock, r, v) pci_write_config_byte((sock)->pdev, r, v) -#define config_writew(sock, r, v) pci_write_config_word((sock)->pdev, r, v) -#define config_writel(sock, r, v) pci_write_config_dword((sock)->pdev, r, v) - -#define cb_readb(s, r) readb(socket[s].cb_virt + (r)) -#define cb_readl(s, r) readl(socket[s].cb_virt + (r)) -#define cb_writeb(s, r, v) writeb(v, socket[s].cb_virt + (r)) -#define cb_writel(s, r, v) writel(v, socket[s].cb_virt + (r)) /*====================================================================*/ diff -u --recursive --new-file v2.3.47/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c --- v2.3.47/linux/drivers/pcmcia/yenta.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/pcmcia/yenta.c Wed Feb 23 08:49:46 2000 @@ -17,6 +17,12 @@ #include "yenta.h" #include "i82365.h" +#if 0 +#define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args) +#else +#define DEBUG(x,args...) +#endif + /* Don't ask.. */ #define to_cycles(ns) ((ns)/120) #define to_ns(cycles) ((cycles)*120) @@ -26,13 +32,24 @@ * regular memory space ("cb_xxx"), configuration space * ("config_xxx") and compatibility space ("exca_xxxx") */ -#define cb_readl(sock,reg) readl((sock)->base + (reg)) -#define cb_writel(sock,reg,val) writel(val,(sock)->base + (reg)) +static inline u32 cb_readl(pci_socket_t *socket, unsigned reg) +{ + u32 val = readl(socket->base + reg); + DEBUG("%p %04x %08x\n", socket, reg, val); + return val; +} + +static inline void cb_writel(pci_socket_t *socket, unsigned reg, u32 val) +{ + DEBUG("%p %04x %08x\n", socket, reg, val); + writel(val, socket->base + reg); +} static inline u8 config_readb(pci_socket_t *socket, unsigned offset) { u8 val; pci_read_config_byte(socket->dev, offset, &val); + DEBUG("%p %04x %02x\n", socket, offset, val); return val; } @@ -40,6 +57,7 @@ { u16 val; pci_read_config_word(socket->dev, offset, &val); + DEBUG("%p %04x %04x\n", socket, offset, val); return val; } @@ -47,25 +65,55 @@ { u32 val; pci_read_config_dword(socket->dev, offset, &val); + DEBUG("%p %04x %08x\n", socket, offset, val); return val; } -#define config_writeb(s,off,val) pci_write_config_byte((s)->dev, (off), (val)) -#define config_writew(s,off,val) pci_write_config_word((s)->dev, (off), (val)) -#define config_writel(s,off,val) pci_write_config_dword((s)->dev, (off), (val)) +static inline void config_writeb(pci_socket_t *socket, unsigned offset, u8 val) +{ + DEBUG("%p %04x %02x\n", socket, offset, val); + pci_write_config_byte(socket->dev, offset, val); +} + +static inline void config_writew(pci_socket_t *socket, unsigned offset, u16 val) +{ + DEBUG("%p %04x %04x\n", socket, offset, val); + pci_write_config_word(socket->dev, offset, val); +} -#define exca_readb(sock,reg) readb((sock)->base + 0x800 + (reg)) -#define exca_writeb(sock,reg,v) writeb((v), (sock)->base + 0x800 + (reg)) +static inline void config_writel(pci_socket_t *socket, unsigned offset, u32 val) +{ + DEBUG("%p %04x %08x\n", socket, offset, val); + pci_write_config_dword(socket->dev, offset, val); +} + +static inline u8 exca_readb(pci_socket_t *socket, unsigned reg) +{ + u8 val = readb(socket->base + 0x800 + reg); + DEBUG("%p %04x %02x\n", socket, reg, val); + return val; +} + +static inline u8 exca_readw(pci_socket_t *socket, unsigned reg) +{ + u16 val; + val = readb(socket->base + 0x800 + reg); + val |= readb(socket->base + 0x800 + reg + 1) << 8; + DEBUG("%p %04x %04x\n", socket, reg, val); + return val; +} -static u16 exca_readw(pci_socket_t *socket, unsigned reg) +static inline void exca_writeb(pci_socket_t *socket, unsigned reg, u8 val) { - return exca_readb(socket, reg) | (exca_readb(socket, reg+1) << 8); + DEBUG("%p %04x %02x\n", socket, reg, val); + writeb(val, socket->base + 0x800 + reg); } static void exca_writew(pci_socket_t *socket, unsigned reg, u16 val) { - exca_writeb(socket, reg, val); - exca_writeb(socket, reg+1, val >> 8); + DEBUG("%p %04x %04x\n", socket, reg, val); + writeb(val, socket->base + 0x800 + reg); + writeb(val >> 8, socket->base + 0x800 + reg + 1); } /* diff -u --recursive --new-file v2.3.47/linux/drivers/pnp/isapnp_proc.c linux/drivers/pnp/isapnp_proc.c --- v2.3.47/linux/drivers/pnp/isapnp_proc.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/pnp/isapnp_proc.c Sat Feb 26 20:33:03 2000 @@ -210,11 +210,6 @@ release: isapnp_info_entry_release, }; -static struct inode_operations isapnp_info_entry_inode_operations = -{ - &isapnp_info_entry_operations, /* default sound info directory file-ops */ -}; - static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence) { loff_t new; @@ -274,11 +269,6 @@ read: isapnp_proc_bus_read, }; -static struct inode_operations isapnp_proc_bus_inode_operations = -{ - &isapnp_proc_bus_file_operations, -}; - static int isapnp_proc_attach_device(struct pci_dev *dev) { struct pci_bus *bus = dev->bus; @@ -295,7 +285,7 @@ e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de); if (!e) return -ENOMEM; - e->ops = &isapnp_proc_bus_inode_operations; + e->proc_fops = &isapnp_proc_bus_file_operations; e->data = dev; e->size = 256; return 0; @@ -378,7 +368,7 @@ isapnp_proc_entry = NULL; p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root); if (p) - p->ops = &isapnp_info_entry_inode_operations; + p->proc_fops = &isapnp_info_entry_operations; isapnp_proc_entry = p; isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus); isapnp_proc_devices_entry = create_proc_info_entry("devices", 0, diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/3w-xxxx.c linux/drivers/scsi/3w-xxxx.c --- v2.3.47/linux/drivers/scsi/3w-xxxx.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/3w-xxxx.c Sat Feb 26 20:32:15 2000 @@ -85,7 +85,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs); /* Globals */ -char *tw_driver_version="0.4.001"; +char *tw_driver_version="1.0.000"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -2051,12 +2051,16 @@ command_packet->status = 0; command_packet->flags = 0; + if ((srb->cmnd[0] == WRITE_6) || (srb->cmnd[0] == WRITE_10)) { + if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10)) + command_packet->flags = 1; + } + if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) { lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | (u32)srb->cmnd[3]; num_sectors = (u32)srb->cmnd[4]; } else { - lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | - ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5]; + lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5]; num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8); } diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx --- v2.3.47/linux/drivers/scsi/ChangeLog.sym53c8xx Tue Jan 11 22:31:41 2000 +++ linux/drivers/scsi/ChangeLog.sym53c8xx Mon Feb 21 17:35:06 2000 @@ -1,3 +1,17 @@ +Sun Feb 20 11:00 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.5j + - Add support for the new dynamic dma mapping kernel interface. + Requires Linux-2.3.47 (tested with pre-2.3.47-6). + Many thanks to David S. Miller for his preliminary changes + that have been useful guidelines, for having reviewed the + code and having tested this driver version on Ultra-Sparc. + - 2 tiny bugs fixed in the PCI wrapper that provides support + for early kernels without pci device structure. + - Get data transfer direction from the scsi command structure + (Scsi_Cmnd) with kernels that provide this information. + - Fix an old bug that only affected 896 rev. 1 when driver + profile support option was set in kernel configuration. + Sat Jan 8 22:00 2000 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.5h - Add year 2000 copyright. diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.3.47/linux/drivers/scsi/Config.in Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/Config.in Sat Feb 26 20:32:15 2000 @@ -34,6 +34,19 @@ mainmenu_option next_comment comment 'SCSI low-level drivers' +if [ "$CONFIG_SGI_IP22" = "y" ]; then + dep_tristate 'SGI WD93C93 SCSI Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI +fi +if [ "$CONFIG_DECSTATION" = "y" ]; then + if [ "$CONFIG_TC" = "y" ]; then + dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI + fi + dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI +fi + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate '3ware Hardware ATA-RAID support (EXPERIMENTAL)' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI +fi dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI dep_tristate 'ACARD SCSI support' CONFIG_SCSI_ACARD $CONFIG_SCSI dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI @@ -177,9 +190,6 @@ fi if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then bool 'MIPS JAZZ FAS216 SCSI support' CONFIG_JAZZ_ESP -fi -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate '3Ware Hardware ATA-RAID support (EXPERIMENTAL)' CONFIG_BLK_DEV_3W_XXXX_RAID $CONFIG_SCSI fi endmenu diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.3.47/linux/drivers/scsi/Makefile Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/Makefile Thu Feb 24 22:51:47 2000 @@ -689,6 +689,10 @@ L_OBJS += NCR53C9x.o jazz_esp.o endif +ifeq ($(CONFIG_SCSI_DECNCR),y) +L_OBJS += NCR53C9x.o dec_esp.o +endif + ifeq ($(CONFIG_SUN3X_ESP),y) L_OBJS += NCR53C9x.o sun3x_esp.o endif diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/dec_esp.c linux/drivers/scsi/dec_esp.c --- v2.3.47/linux/drivers/scsi/dec_esp.c Fri Oct 15 15:25:14 1999 +++ linux/drivers/scsi/dec_esp.c Thu Feb 24 22:51:47 2000 @@ -1,7 +1,9 @@ /* * dec_esp.c: Driver for SCSI chips on IOASIC based TURBOchannel DECstations + * and TURBOchannel PMAZ-A cards * * TURBOchannel changes by Harald Koerfgen + * PMAZ-A support by David Airlie * * based on jazz_esp.c: * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) @@ -38,21 +40,43 @@ static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count); static void dma_drain(struct NCR_ESP *esp); +static void pmaz_dma_drain(struct NCR_ESP *esp); static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp); static void dma_dump_state(struct NCR_ESP *esp); static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); static void dma_ints_off(struct NCR_ESP *esp); static void dma_ints_on(struct NCR_ESP *esp); +static void pmaz_dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length); +static void pmaz_dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length); +static void pmaz_dma_ints_off(struct NCR_ESP *esp); +static void pmaz_dma_ints_on(struct NCR_ESP *esp); static int dma_irq_p(struct NCR_ESP *esp); static int dma_ports_p(struct NCR_ESP *esp); static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp); static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp); +static void pmaz_dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write); +static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp); +// static void pmaz_dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd * sp); static void dma_advance_sg(Scsi_Cmnd * sp); +#define TC_ESP_RAM_SIZE 0x20000 +#define ESP_TGT_DMA_SIZE ((TC_ESP_RAM_SIZE/7) & ~(sizeof(int)-1)) +#define ESP_NCMD 7 + +#define TC_ESP_DMAR_MASK 0x1ffff +#define TC_ESP_DMAR_WRITE 0x80000000 +#define TC_ESP_DMA_ADDR(x) ((unsigned)(x) & TC_ESP_DMAR_MASK) + +volatile unsigned char *scsi_pmaz_dma_ptrs_tc[ESP_NCMD]; +unsigned char scsi_pmaz_dma_buff_used[ESP_NCMD]; +unsigned char scsi_cur_buff = 1; /* Leave space for command buffer */ +__u32 esp_virt_buffer; +int scsi_current_length = 0; volatile unsigned char cmd_buffer[16]; +volatile unsigned char pmaz_cmd_buffer[16]; /* This is where all commands are put * before they are trasfered to the ESP chip * via PIO. @@ -65,6 +89,8 @@ volatile unsigned long *scsi_sdr0; volatile unsigned long *scsi_sdr1; +volatile int *scsi_pmaz_dma_ptr_tc; + static void scsi_dma_int(int, void *, struct pt_regs *); /***************************************************************** Detection */ @@ -72,6 +98,9 @@ { struct NCR_ESP *esp; struct ConfigDev *esp_dev; + int slot, i; + unsigned long mem_start; + volatile unsigned char *buffer; if (IOASIC) { esp_dev = 0; @@ -143,21 +172,88 @@ request_irq(SCSI_DMA_INT, scsi_dma_int, SA_INTERRUPT, "JUNKIO SCSI DMA", NULL); - /* - * FIXME, look if the scsi id is availabe from NVRAM - */ esp->scsi_id = 7; /* Check for differential SCSI-bus */ - /* What is this stuff? */ esp->diff = 0; esp_initialize(esp); + } + + if (TURBOCHANNEL) { + while ((slot = search_tc_card("PMAZ-AA")) >= 0) { + claim_tc_card(slot); + mem_start = get_tc_base_addr(slot); + + esp_dev = 0; + esp = esp_allocate(tpnt, (void *) esp_dev); + + esp->dregs = 0; + esp->eregs = (struct ESP_regs *) (mem_start + DEC_SCSI_SREG); + esp->do_pio_cmds = 1; + + /* Set the command buffer */ + esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer; + + /* get virtual dma address for command buffer */ + esp->esp_command_dvma = (__u32) KSEG0ADDR((volatile unsigned char *) pmaz_cmd_buffer); + + buffer = (volatile unsigned char *) (mem_start + DEC_SCSI_SRAM); + + scsi_pmaz_dma_ptr_tc = (volatile int *) (mem_start + DEC_SCSI_DMAREG); + + for (i = 0; i < ESP_NCMD; i++) { + scsi_pmaz_dma_ptrs_tc[i] = (volatile unsigned char *) (buffer + ESP_TGT_DMA_SIZE * i); + } + + scsi_pmaz_dma_buff_used[0] = 1; + + esp->cfreq = get_tc_speed(); + + esp->irq = get_tc_irq_nr(slot); + + /* Required functions */ + esp->dma_bytes_sent = &dma_bytes_sent; + esp->dma_can_transfer = &dma_can_transfer; + esp->dma_dump_state = &dma_dump_state; + esp->dma_init_read = &pmaz_dma_init_read; + esp->dma_init_write = &pmaz_dma_init_write; + esp->dma_ints_off = &pmaz_dma_ints_off; + esp->dma_ints_on = &pmaz_dma_ints_on; + esp->dma_irq_p = &dma_irq_p; + esp->dma_ports_p = &dma_ports_p; + esp->dma_setup = &pmaz_dma_setup; + + /* Optional functions */ + esp->dma_barrier = 0; + esp->dma_drain = &pmaz_dma_drain; + esp->dma_invalidate = 0; + esp->dma_irq_entry = 0; + esp->dma_irq_exit = 0; + esp->dma_poll = 0; + esp->dma_reset = 0; + esp->dma_led_off = 0; + esp->dma_led_on = 0; + + esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one; + esp->dma_mmu_get_scsi_sgl = 0; + esp->dma_mmu_release_scsi_one = 0; + esp->dma_mmu_release_scsi_sgl = 0; + esp->dma_advance_sg = 0; + + request_irq(esp->irq, esp_intr, SA_INTERRUPT, "PMAZ-AA", NULL); + esp->scsi_id = 7; + esp->diff = 0; + esp_initialize(esp); + } + } + + if(nesps) { printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use); esps_running = esps_in_use; return esps_in_use; - } + } else return 0; } @@ -172,18 +268,18 @@ *scsi_next_ptr = ((*scsi_dma_ptr + PAGE_SIZE) & PAGE_MASK) << 3; *isr &= ~SCSI_PTR_LOADED; } else { - printk("Got unexpected SCSI DMA Interrupt! < "); if (*isr & SCSI_PAGOVRRUN) - printk("SCSI_PAGOVRRUN "); - if (*isr & SCSI_DMA_MEMRDERR) + *isr &= ~SCSI_PAGOVRRUN; + if (*isr & SCSI_DMA_MEMRDERR) { + printk("Got unexpected SCSI DMA Interrupt! < "); printk("SCSI_DMA_MEMRDERR "); printk(">\n"); -// panic("stop"); - *isr &= ~(SCSI_PAGOVRRUN || SCSI_DMA_MEMRDERR); + *isr &= ~SCSI_DMA_MEMRDERR; + } } /* - * This driver will only work on IOASIC machines + * This routine will only work on IOASIC machines * so we can avoid an indirect function call here * and flush the writeback buffer the fast way */ @@ -198,13 +294,13 @@ static void dma_drain(struct NCR_ESP *esp) { - unsigned long nw; + unsigned long nw = *scsi_scr; unsigned short *p = KSEG1ADDR((unsigned short *) ((*scsi_dma_ptr) >> 3)); /* * Is there something in the dma buffers left? */ - if (nw = *scsi_scr) { + if (nw) { switch (nw) { case 1: *p = (unsigned short) *scsi_sdr0; @@ -225,6 +321,12 @@ } } +static void pmaz_dma_drain(struct NCR_ESP *esp) +{ + memcpy((volatile void *) (KSEG0ADDR(esp_virt_buffer)), + (void *) scsi_pmaz_dma_ptrs_tc[scsi_cur_buff], scsi_current_length); +} + static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp) { return sp->SCp.this_residual;; @@ -298,6 +400,33 @@ enable_irq(SCSI_DMA_INT); } +static void pmaz_dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) +{ + + if (length > ESP_TGT_DMA_SIZE) + length = ESP_TGT_DMA_SIZE; + + *scsi_pmaz_dma_ptr_tc = TC_ESP_DMA_ADDR(scsi_pmaz_dma_ptrs_tc[scsi_cur_buff]); + esp_virt_buffer = vaddress; + scsi_current_length = length; +} + +static void pmaz_dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length) +{ + memcpy(scsi_pmaz_dma_ptrs_tc[scsi_cur_buff], KSEG0ADDR((void *) vaddress), length); + + *scsi_pmaz_dma_ptr_tc = TC_ESP_DMAR_WRITE | TC_ESP_DMA_ADDR(scsi_pmaz_dma_ptrs_tc[scsi_cur_buff]); + +} + +static void pmaz_dma_ints_off(struct NCR_ESP *esp) +{ +} + +static void pmaz_dma_ints_on(struct NCR_ESP *esp) +{ +} + static int dma_irq_p(struct NCR_ESP *esp) { return (esp->eregs->esp_status & ESP_STAT_INTR); @@ -322,6 +451,34 @@ } else { dma_init_write(esp, addr, count); } +} + +static void pmaz_dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write) +{ + /* + * On the Sparc, DMA_ST_WRITE means "move data from device to memory" + * so when (write) is true, it actually means READ! + */ + if (write) { + pmaz_dma_init_read(esp, addr, count); + } else { + pmaz_dma_init_write(esp, addr, count); + } +} + +static void pmaz_dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp) +{ + int x; + for (x = 1; x < 6; x++) + if (sp->SCp.have_data_in == PHYSADDR(scsi_pmaz_dma_ptrs_tc[x])) + scsi_pmaz_dma_buff_used[x] = 0; +} + + +static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd * sp) +{ + sp->SCp.have_data_in = (int) sp->SCp.ptr = + (char *) KSEG0ADDR((sp->request_buffer)); } /* diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/dec_esp.h linux/drivers/scsi/dec_esp.h --- v2.3.47/linux/drivers/scsi/dec_esp.h Thu Nov 11 20:11:46 1999 +++ linux/drivers/scsi/dec_esp.h Thu Feb 24 22:51:47 2000 @@ -1,6 +1,7 @@ /* dec_esp.h: Defines and structures for the JAZZ SCSI driver. * * DECstation changes Copyright (C) 1998 Harald Koerfgen + * and David Airlie * * based on jazz_esp.h: * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) @@ -9,10 +10,12 @@ #ifndef DEC_ESP_H #define DEC_ESP_H -#define EREGS_PAD(n) unchar n[3]; - #include "NCR53C9x.h" +#define DEC_SCSI_SREG 0 +#define DEC_SCSI_DMAREG 0x40000 +#define DEC_SCSI_SRAM 0x80000 +#define DEC_SCSI_DIAG 0xC0000 extern int dec_esp_detect(struct SHT *); extern const char *esp_info(struct Scsi_Host *); @@ -26,7 +29,7 @@ #define SCSI_DEC_ESP { \ proc_name: "esp", \ proc_info: &esp_proc_info, \ - name: "PMAZ-AA", \ + name: "NCR53C94", \ detect: dec_esp_detect, \ info: esp_info, \ command: esp_command, \ diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/eata_dma_proc.c linux/drivers/scsi/eata_dma_proc.c --- v2.3.47/linux/drivers/scsi/eata_dma_proc.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/eata_dma_proc.c Fri Feb 25 10:32:09 2000 @@ -167,7 +167,7 @@ cmnd[9] = 0; scmd->cmd_len = 10; - scmd->sc_data_direction = DATA_READ; + scmd->sc_data_direction = SCSI_DATA_READ; /* * Do the command and wait for it to finish. diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.3.47/linux/drivers/scsi/hosts.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/hosts.c Thu Feb 24 22:51:47 2000 @@ -345,6 +345,10 @@ #include "jazz_esp.h" #endif +#ifdef CONFIG_SCSI_DECNCR +#include "dec_esp.h" +#endif + #ifdef CONFIG_SUN3X_ESP #include "sun3x_esp.h" #endif @@ -638,10 +642,12 @@ #ifdef CONFIG_IPHASE5526 IPH5526_SCSI_FC, #endif +#ifdef CONFIG_SCSI_DECNCR + SCSI_DEC_ESP, +#endif #ifdef CONFIG_BLK_DEV_3W_XXXX_RAID TWXXXX, #endif - /* "Removable host adapters" below this line (Parallel Port/USB/other) */ #ifdef CONFIG_SCSI_PPA PPA, diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/jazz_esp.c linux/drivers/scsi/jazz_esp.c --- v2.3.47/linux/drivers/scsi/jazz_esp.c Wed Aug 18 10:00:52 1999 +++ linux/drivers/scsi/jazz_esp.c Thu Feb 24 22:51:47 2000 @@ -1,7 +1,7 @@ /* * jazz_esp.c: Driver for SCSI chip on Mips Magnum Boards (JAZZ architecture) * - * Copyright (C) 1997 Thomas Boegndoerfer (tsbogend@alpha.franken.de) + * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de) * * jazz_esp is based on David S. Miller's ESP driver and cyber_esp */ @@ -161,7 +161,7 @@ { ESPLOG(("esp%d: dma -- enable <%08x> residue <%08x\n", - esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_resdiue((int)esp->dregs))); + esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_residue((int)esp->dregs))); } static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length) diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/jazz_esp.h linux/drivers/scsi/jazz_esp.h --- v2.3.47/linux/drivers/scsi/jazz_esp.h Thu Nov 11 20:11:47 1999 +++ linux/drivers/scsi/jazz_esp.h Thu Feb 24 22:51:47 2000 @@ -37,4 +37,3 @@ use_clustering: DISABLE_CLUSTERING, } #endif /* JAZZ_ESP_H */ - diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c --- v2.3.47/linux/drivers/scsi/pci2000.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/pci2000.c Sat Feb 26 20:33:03 2000 @@ -60,9 +60,6 @@ #include #endif -struct proc_dir_entry Proc_Scsi_Pci2000 = - { PROC_SCSI_PCI2000, 7, "pci2000", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; - //#define DEBUG 1 #ifdef DEBUG diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/pci2000.h linux/drivers/scsi/pci2000.h --- v2.3.47/linux/drivers/scsi/pci2000.h Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/pci2000.h Sat Feb 26 20:48:05 2000 @@ -200,59 +200,25 @@ #define NULL 0 #endif -extern struct proc_dir_entry Proc_Scsi_Pci2000; - -#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75) -#define PCI2000 { \ - next: NULL, \ - module: NULL, \ - proc_dir: &Proc_Scsi_Pci2000, \ - proc_info: NULL, /* let's not bloat the kernel */ \ - name: "PCI-2000 SCSI Intelligent Disk Controller",\ - detect: Pci2000_Detect, \ - release: Pci2000_Release, \ - info: NULL, /* let's not bloat the kernel */ \ - command: Pci2000_Command, \ - queuecommand: Pci2000_QueueCommand, \ - eh_strategy_handler: NULL, \ - eh_abort_handler: NULL, \ - eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: NULL, \ - eh_host_reset_handler: NULL, \ - abort: Pci2000_Abort, \ - reset: Pci2000_Reset, \ - slave_attach: NULL, \ - bios_param: Pci2000_BiosParam, \ - can_queue: 16, \ - this_id: -1, \ - sg_tablesize: 16, \ - cmd_per_lun: 1, \ - present: 0, \ - unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING, \ - use_new_eh_code: 0 \ - } -#else -#define PCI2000 { NULL, NULL, \ - &Proc_Scsi_Pci2000,/* proc_dir_entry */ \ - NULL, \ - "PCI-2000 SCSI Intelligent Disk Controller",\ - Pci2000_Detect, \ - Pci2000_Release, \ - NULL, \ - Pci2000_Command, \ - Pci2000_QueueCommand, \ - Pci2000_Abort, \ - Pci2000_Reset, \ - NULL, \ - Pci2000_BiosParam, \ - 16, \ - -1, \ - 16, \ - 1, \ - 0, \ - 0, \ - DISABLE_CLUSTERING } -#endif +/* screen is 80 columns wide, damnit! */ +#define PCI2000 { \ + proc_name: "pci2000", \ + name: "PCI-2000 SCSI Intelligent Disk Controller", \ + detect: Pci2000_Detect, \ + release: Pci2000_Release, \ + command: Pci2000_Command, \ + queuecommand: Pci2000_QueueCommand, \ + abort: Pci2000_Abort, \ + reset: Pci2000_Reset, \ + bios_param: Pci2000_BiosParam, \ + can_queue: 16, \ + this_id: -1, \ + sg_tablesize: 16, \ + cmd_per_lun: 1, \ + present: 0, \ + unchecked_isa_dma:0, \ + use_clustering: DISABLE_CLUSTERING, \ + use_new_eh_code:0 \ +} #endif diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.3.47/linux/drivers/scsi/pci2220i.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/pci2220i.c Sat Feb 26 20:33:03 2000 @@ -67,9 +67,6 @@ #define WRITE_CMD IDE_CMD_WRITE_MULTIPLE #define MAX_BUS_MASTER_BLOCKS SECTORSXFER // This is the maximum we can bus master -struct proc_dir_entry Proc_Scsi_Pci2220i = - { PROC_SCSI_PCI2220I, 8, "pci2220i", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; - #ifdef DEBUG #define DEB(x) x #define STOP_HERE() {int st;for(st=0;st<100;st++){st=1;}} diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/pci2220i.h linux/drivers/scsi/pci2220i.h --- v2.3.47/linux/drivers/scsi/pci2220i.h Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/pci2220i.h Sat Feb 26 20:48:07 2000 @@ -39,59 +39,23 @@ #define NULL 0 #endif -extern struct proc_dir_entry Proc_Scsi_Pci2220i; - -#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75) -#define PCI2220I { \ - next: NULL, \ - module: NULL, \ - proc_dir: &Proc_Scsi_Pci2220i, \ - proc_info: NULL, /* let's not bloat the kernel */\ - name: "PCI-2220I/PCI-2240I", \ - detect: Pci2220i_Detect, \ - release: Pci2220i_Release, \ - info: NULL, /* let's not bloat the kernel */\ - command: Pci2220i_Command, \ - queuecommand: Pci2220i_QueueCommand, \ - eh_strategy_handler: NULL, \ - eh_abort_handler: NULL, \ - eh_device_reset_handler: NULL, \ - eh_bus_reset_handler: NULL, \ - eh_host_reset_handler: NULL, \ - abort: Pci2220i_Abort, \ - reset: Pci2220i_Reset, \ - slave_attach: NULL, \ - bios_param: Pci2220i_BiosParam, \ - can_queue: 1, \ - this_id: -1, \ - sg_tablesize: SG_ALL, \ - cmd_per_lun: 1, \ - present: 0, \ - unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING, \ - use_new_eh_code: 0 \ - } -#else -#define PCI2220I { NULL, NULL, \ - &Proc_Scsi_Pci2220i,/* proc_dir_entry */\ - NULL, \ - "PCI-2220I/PCI-2240I", \ - Pci2220i_Detect, \ - Pci2220i_Release, \ - NULL, \ - Pci2220i_Command, \ - Pci2220i_QueueCommand, \ - Pci2220i_Abort, \ - Pci2220i_Reset, \ - NULL, \ - Pci2220i_BiosParam, \ - 1, \ - -1, \ - SG_ALL, \ - 1, \ - 0, \ - 0, \ - DISABLE_CLUSTERING } -#endif - +#define PCI2220I { \ + proc_name: "pci2220i", \ + name: "PCI-2220I/PCI-2240I", \ + detect: Pci2220i_Detect, \ + release: Pci2220i_Release, \ + command: Pci2220i_Command, \ + queuecommand: Pci2220i_QueueCommand, \ + abort: Pci2220i_Abort, \ + reset: Pci2220i_Reset, \ + bios_param: Pci2220i_BiosParam, \ + can_queue: 1, \ + this_id: -1, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING, \ + use_new_eh_code: 0 \ +} #endif diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c --- v2.3.47/linux/drivers/scsi/qla1280.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/scsi/qla1280.c Sat Feb 26 20:33:03 2000 @@ -426,25 +426,6 @@ #endif - -/* - * Our directory Entry in /proc/scsi for the user to - * access the driver. - */ - -#if 0 - -/* Need to add in proc_fs.h PROC_SCSI_QL1280 */ -#define PROC_SCSI_QL1280 PROC_SCSI_QLOGICISP - -struct proc_dir_entry proc_scsi_qla1280 = { - PROC_SCSI_QL1280, 7, "qla1280", - S_IFDIR | S_IRUGO | S_IXUGO, 2, - 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -#endif - /* We use the Scsi_Pointer structure that's included with each command * SCSI_Cmnd as a scratchpad for our SRB. * @@ -2749,13 +2730,13 @@ long risc_code_size; uint16_t mb[MAILBOX_REGISTER_COUNT]; #ifdef QLA1280_UNUSED + uint8_t *sp; int i; #endif uint16_t cnt; int num; - uint8_t *tbuf, *sp; + uint8_t *tbuf; u_long p_tbuf; - int i; #ifdef QL_DEBUG_LEVEL_3 ENTER("qla1280_setup_chip"); diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- v2.3.47/linux/drivers/scsi/qlogicfc.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/qlogicfc.c Wed Feb 23 13:37:35 2000 @@ -18,6 +18,9 @@ /* This is a version of the isp1020 driver which was modified by * Chris Loveland to support the isp2100 and isp2200 + * + * Big endian support and dynamic DMA mapping added + * by Jakub Jelinek . */ /* @@ -59,6 +62,24 @@ #include "sd.h" #include "hosts.h" + +#if 1 +/* Once pci64_ DMA mapping interface is in, kill this. */ +typedef dma_addr_t dma64_addr_t; +#define pci64_alloc_consistent(d,s,p) pci_alloc_consistent((d),(s),(p)) +#define pci64_free_consistent(d,s,c,a) pci_free_consistent((d),(s),(c),(a)) +#define pci64_map_single(d,c,s,dir) pci_map_single((d),(c),(s),(dir)) +#define pci64_map_sg(d,s,n,dir) pci_map_sg((d),(s),(n),(dir)) +#define pci64_unmap_single(d,a,s,dir) pci_unmap_single((d),(a),(s),(dir)) +#define pci64_unmap_sg(d,s,n,dir) pci_unmap_sg((d),(s),(n),(dir)) +#define pci64_dma_hi32(a) 0 +#define pci64_dma_lo32(a) (a) +#define pci64_dma_build(hi,lo) (lo) +#define sg_dma64_address(s) sg_dma_address(s) +#define sg_dma64_len(s) sg_dma_len(s) +#define PCI64_DMA_BITS 32 +#endif + #include "qlogicfc.h" /* Configuration section **************************************************** */ @@ -157,18 +178,6 @@ #endif /* DEBUG ISP2x00_INTR */ -#if BITS_PER_LONG > 32 -#define virt_to_bus_low32(x) ((u32) (0xffffffff & virt_to_bus(x))) -#define virt_to_bus_high32(x) ((u32) (0xffffffff & (virt_to_bus(x)>>32))) -#define bus_to_virt_low32(x) ((u32) (0xffffffff & bus_to_virt(x))) -#define bus_to_virt_high32(x) ((u32) (0xffffffff & (bus_to_virt(x)>>32))) -#else -#define virt_to_bus_low32(x) virt_to_bus(x) -#define virt_to_bus_high32(x) 0x0 -#define bus_to_virt_low32(x) bus_to_virt(x) -#define bus_to_virt_high32(x) 0x0 -#endif - #define ISP2100_REV_ID1 1 #define ISP2100_REV_ID3 3 #define ISP2200_REV_ID5 5 @@ -230,7 +239,7 @@ }; /* entry header type commands */ -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 #define ENTRY_COMMAND 0x19 #define ENTRY_CONTINUATION 0x0a #else @@ -247,34 +256,23 @@ #define EFLAG_BAD_HEADER 4 #define EFLAG_BAD_PAYLOAD 8 -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 + struct dataseg { u_int d_base; u_int d_base_hi; u_int d_count; }; -struct Command_Entry { - struct Entry_header hdr; - u_int handle; - u_char target_lun; - u_char target_id; - u_short expanded_lun; - u_short control_flags; - u_short rsvd2; - u_short time_out; - u_short segment_cnt; - u_char cdb[16]; - u_int total_byte_cnt; - struct dataseg dataseg[DATASEGS_PER_COMMAND]; -}; - #else + struct dataseg { u_int d_base; u_int d_count; }; +#endif + struct Command_Entry { struct Entry_header hdr; u_int handle; @@ -290,9 +288,6 @@ struct dataseg dataseg[DATASEGS_PER_COMMAND]; }; -#endif - - /* command entry control flag definitions */ #define CFLAG_NODISC 0x01 #define CFLAG_HEAD_TAG 0x02 @@ -302,7 +297,7 @@ #define CFLAG_READ 0x20 #define CFLAG_WRITE 0x40 -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 struct Continuation_Entry { struct Entry_header hdr; struct dataseg dataseg[DATASEGS_PER_CONT]; @@ -650,6 +645,9 @@ #define AS_REDO_FABRIC_PORTDB 2 #define AS_REDO_LOOP_PORTDB 4 +#define RES_SIZE ((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN) +#define REQ_SIZE ((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN) + struct isp2x00_hostdata { u_char revision; struct pci_dev *pci_dev; @@ -730,6 +728,7 @@ struct isp2x00_hostdata *hostdata; struct pci_dev *pdev = NULL; unsigned short device_ids[2]; + dma64_addr_t busaddr; int i; @@ -756,50 +755,43 @@ memset(hostdata, 0, sizeof(struct isp2x00_hostdata)); hostdata->pci_dev = pdev; - hostdata->res = (char *) kmalloc((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN, GFP_KERNEL); + hostdata->res = pci64_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr); + if (!hostdata->res){ - printk("qlogicfc%d : could not allocate memory for response queue.\n", hostdata->host_id); + printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hostdata->host_id); scsi_unregister(host); continue; } - hostdata->req = (char *) kmalloc((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN, GFP_KERNEL); - if (!hostdata->req){ - printk("qlogicfc%d : could not allocate memory for request queue.\n", hostdata->host_id); - kfree(hostdata->res); - scsi_unregister(host); - continue; - } - + hostdata->req = hostdata->res + (RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN; hostdata->queued = 0; /* set up the control block */ hostdata->control_block.version = 0x1; - hostdata->control_block.firm_opts = 0x800e; - hostdata->control_block.max_frame_len = 2048; - hostdata->control_block.max_iocb = QLOGICFC_REQ_QUEUE_LEN; - hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN; + hostdata->control_block.firm_opts = cpu_to_le16(0x800e); + hostdata->control_block.max_frame_len = cpu_to_le16(2048); + hostdata->control_block.max_iocb = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN); + hostdata->control_block.exec_throttle = cpu_to_le16(QLOGICFC_CMD_PER_LUN); hostdata->control_block.retry_delay = 5; hostdata->control_block.retry_cnt = 1; - hostdata->control_block.node_name[0] = 0x0020; - hostdata->control_block.node_name[1] = 0xE000; - hostdata->control_block.node_name[2] = 0x008B; - hostdata->control_block.node_name[3] = 0x0000; - hostdata->control_block.hard_addr = 0x0003; - hostdata->control_block.req_queue_len = QLOGICFC_REQ_QUEUE_LEN + 1; - hostdata->control_block.res_queue_len = RES_QUEUE_LEN + 1; - hostdata->control_block.res_queue_addr_lo = virt_to_bus_low32(hostdata->res); - hostdata->control_block.res_queue_addr_high = virt_to_bus_high32(hostdata->res); - hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(hostdata->req); - hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(hostdata->req); + hostdata->control_block.node_name[0] = cpu_to_le16(0x0020); + hostdata->control_block.node_name[1] = cpu_to_le16(0xE000); + hostdata->control_block.node_name[2] = cpu_to_le16(0x008B); + hostdata->control_block.node_name[3] = cpu_to_le16(0x0000); + hostdata->control_block.hard_addr = cpu_to_le16(0x0003); + hostdata->control_block.req_queue_len = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN + 1); + hostdata->control_block.res_queue_len = cpu_to_le16(RES_QUEUE_LEN + 1); + hostdata->control_block.res_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr)); + hostdata->control_block.res_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr)); + hostdata->control_block.req_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr + RES_SIZE)); + hostdata->control_block.req_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr + RES_SIZE)); - hostdata->control_block.add_firm_opts |= CONNECTION_PREFERENCE<<4; + hostdata->control_block.add_firm_opts |= cpu_to_le16(CONNECTION_PREFERENCE<<4); hostdata->adapter_state = AS_LOOP_DOWN; hostdata->explore_timer.data = 1; hostdata->host_id = hosts; if (isp2x00_init(host) || isp2x00_reset_hardware(host)) { - kfree(hostdata->res); - kfree(hostdata->req); + pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -808,8 +800,7 @@ if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { printk("qlogicfc%d : interrupt %d already in use\n", hostdata->host_id, host->irq); - kfree(hostdata->res); - kfree(hostdata->req); + pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -818,8 +809,7 @@ "in use\n", hostdata->host_id, host->io_port, host->io_port + 0xff); free_irq(host->irq, host); - kfree(hostdata->res); - kfree(hostdata->req); + pci64_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); scsi_unregister(host); continue; } @@ -977,12 +967,13 @@ u_short loop_id = 0x81; u_short scsi_id = cur_scsi_id; u_int port_id; - struct sns_cb req; - u_char sns_response[608]; + struct sns_cb *req; + u_char *sns_response; + dma64_addr_t busaddr; struct isp2x00_hostdata *hostdata; hostdata = (struct isp2x00_hostdata *) host->hostdata; - + DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id)); param[0] = MBOX_GET_PORT_NAME; param[1] = (u16)FABRIC_PORT << 8; @@ -995,52 +986,60 @@ } printk("qlogicfc%d : Fabric found.\n", hostdata->host_id); + req = (struct sns_cb *)pci64_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr); + + if (!req){ + printk("qlogicfc%d : Could not allocate DMA resources for fabric initialization\n", hostdata->host_id); + return 0; + } + sns_response = (u_char *)(req + 1); + if (hostdata->adapter_state & AS_REDO_LOOP_PORTDB){ - memset(&req, 0, sizeof(req)); + memset(req, 0, sizeof(*req)); - req.len = 8; - req.response_low = virt_to_bus_low32(sns_response); - req.response_high = virt_to_bus_high32(sns_response); - req.sub_len = 22; - req.data[0] = 0x17; - req.data[1] = 0x02; - req.data[8] = (u_char) (hostdata->port_id & 0xff); - req.data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); - req.data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); - req.data[13] = 0x01; + req->len = cpu_to_le16(8); + req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req))); + req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req))); + req->sub_len = cpu_to_le16(22); + req->data[0] = 0x17; + req->data[1] = 0x02; + req->data[8] = (u_char) (hostdata->port_id & 0xff); + req->data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); + req->data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); + req->data[13] = 0x01; param[0] = MBOX_SEND_SNS; param[1] = 30; - param[2] = virt_to_bus_low32(&req) >> 16; - param[3] = virt_to_bus_low32(&req); - param[6] = virt_to_bus_high32(&req) >> 16; - param[7] = virt_to_bus_high32(&req); - + param[2] = pci64_dma_lo32(busaddr) >> 16; + param[3] = pci64_dma_lo32(busaddr); + param[6] = pci64_dma_hi32(busaddr) >> 16; + param[7] = pci64_dma_hi32(busaddr); + isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) - printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); + printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); } port_id = hostdata->port_id; while (!done) { - memset(&req, 0, sizeof(req)); + memset(req, 0, sizeof(*req)); - req.len = 304; - req.response_low = virt_to_bus_low32(sns_response); - req.response_high = virt_to_bus_high32(sns_response); - req.sub_len = 6; - req.data[0] = 0x00; - req.data[1] = 0x01; - req.data[8] = (u_char) (port_id & 0xff); - req.data[9] = (u_char) (port_id >> 8 & 0xff); - req.data[10] = (u_char) (port_id >> 16 & 0xff); + req->len = cpu_to_le16(304); + req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req))); + req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req))); + req->sub_len = cpu_to_le16(6); + req->data[0] = 0x00; + req->data[1] = 0x01; + req->data[8] = (u_char) (port_id & 0xff); + req->data[9] = (u_char) (port_id >> 8 & 0xff); + req->data[10] = (u_char) (port_id >> 16 & 0xff); param[0] = MBOX_SEND_SNS; param[1] = 14; - param[2] = virt_to_bus_low32(&req) >> 16; - param[3] = virt_to_bus_low32(&req); - param[6] = virt_to_bus_high32(&req) >> 16; - param[7] = virt_to_bus_high32(&req); + param[2] = pci64_dma_lo32(busaddr) >> 16; + param[3] = pci64_dma_lo32(busaddr); + param[6] = pci64_dma_hi32(busaddr) >> 16; + param[7] = pci64_dma_hi32(busaddr); isp2x00_mbox_command(host, param); @@ -1089,10 +1088,12 @@ done = 1; } else { printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]); + pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); return 0; } } + pci64_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); return 1; } @@ -1102,6 +1103,7 @@ int isp2x00_release(struct Scsi_Host *host) { struct isp2x00_hostdata *hostdata; + dma64_addr_t busaddr; ENTER("isp2x00_release"); @@ -1112,8 +1114,9 @@ release_region(host->io_port, 0xff); - kfree(hostdata->res); - kfree(hostdata->req); + busaddr = pci64_dma_build(le32_to_cpu(hostdata->control_block.res_queue_addr_high), + le32_to_cpu(hostdata->control_block.res_queue_addr_lo)); + pci64_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); LEAVE("isp2x00_release"); @@ -1245,19 +1248,20 @@ cmd->hdr.entry_type = ENTRY_COMMAND; cmd->hdr.entry_cnt = 1; cmd->target_lun = Cmnd->lun; - cmd->expanded_lun = Cmnd->lun; + cmd->expanded_lun = cpu_to_le16(Cmnd->lun); #if ISP2x00_PORTDB cmd->target_id = hostdata->port_db[Cmnd->target].loop_id; #else cmd->target_id = Cmnd->target; #endif - cmd->total_byte_cnt = (u_int) Cmnd->request_bufflen; + cmd->total_byte_cnt = cpu_to_le32(Cmnd->request_bufflen); cmd->time_out = 0; memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); if (Cmnd->use_sg) { - cmd->segment_cnt = sg_count = Cmnd->use_sg; sg = (struct scatterlist *) Cmnd->request_buffer; + sg_count = pci64_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + cmd->segment_cnt = cpu_to_le16(sg_count); ds = cmd->dataseg; /* fill in first two sg entries: */ n = sg_count; @@ -1265,11 +1269,11 @@ n = DATASEGS_PER_COMMAND; for (i = 0; i < n; i++) { - ds[i].d_base = virt_to_bus_low32(sg->address); -#if BITS_PER_LONG > 32 - ds[i].d_base_hi = virt_to_bus_high32(sg->address); + ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg))); +#if PCI64_DMA_BITS > 32 + ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg))); #endif - ds[i].d_count = sg->length; + ds[i].d_count = cpu_to_le32(sg_dma64_len(sg)); ++sg; } sg_count -= DATASEGS_PER_COMMAND; @@ -1291,22 +1295,32 @@ if (n > DATASEGS_PER_CONT) n = DATASEGS_PER_CONT; for (i = 0; i < n; ++i) { - ds[i].d_base = virt_to_bus_low32(sg->address); -#if BITS_PER_LONG > 32 - ds[i].d_base_hi = virt_to_bus_high32(sg->address); + ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma64_address(sg))); +#if PCI64_DMA_BITS > 32 + ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma64_address(sg))); #endif - ds[i].d_count = sg->length; + ds[i].d_count = cpu_to_le32(sg_dma64_len(sg)); ++sg; } sg_count -= n; } + } else if (Cmnd->request_bufflen) { + dma64_addr_t busaddr = pci64_map_single(hostdata->pci_dev, Cmnd->request_buffer, Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + + *(dma64_addr_t *)&Cmnd->SCp = busaddr; + cmd->dataseg[0].d_base = cpu_to_le32(pci64_dma_lo32(busaddr)); +#if PCI64_DMA_BITS > 32 + cmd->dataseg[0].d_base_hi = cpu_to_le32(pci64_dma_hi32(busaddr)); +#endif + cmd->dataseg[0].d_count = cpu_to_le32(Cmnd->request_bufflen); + cmd->segment_cnt = cpu_to_le16(1); } else { - cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->request_buffer); -#if BITS_PER_LONG > 32 - cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer); + cmd->dataseg[0].d_base = 0; +#if PCI64_DMA_BITS > 32 + cmd->dataseg[0].d_base_hi = 0; #endif - cmd->dataseg[0].d_count = (u_int) Cmnd->request_bufflen; - cmd->segment_cnt = 1; + cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */ } switch (Cmnd->cmnd[0]) { @@ -1317,38 +1331,28 @@ case WRITE_6: case WRITE_BUFFER: case MODE_SELECT: - cmd->control_flags = CFLAG_WRITE; - break; - case REQUEST_SENSE: - /* scsi.c expects sense info in a different buffer */ - cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer); -#if BITS_PER_LONG > 32 - cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->sense_buffer); -#endif - cmd->dataseg[0].d_count = sizeof(Cmnd->sense_buffer); - cmd->segment_cnt = 1; - cmd->control_flags = CFLAG_READ; + cmd->control_flags = cpu_to_le16(CFLAG_WRITE); break; default: - cmd->control_flags = CFLAG_READ; + cmd->control_flags = cpu_to_le16(CFLAG_READ); break; } if (Cmnd->device->tagged_supported) { if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (2 * SCSI_TIMEOUT)) { - cmd->control_flags |= CFLAG_ORDERED_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG); hostdata->tag_ages[Cmnd->target] = jiffies; } else switch (Cmnd->tag) { case HEAD_OF_QUEUE_TAG: - cmd->control_flags |= CFLAG_HEAD_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_HEAD_TAG); break; case ORDERED_QUEUE_TAG: - cmd->control_flags |= CFLAG_ORDERED_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG); break; default: - cmd->control_flags |= CFLAG_SIMPLE_TAG; + cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG); break; } } @@ -1543,6 +1547,16 @@ if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[sts->handle])) { Cmnd->result = isp2x00_return_status(Cmnd, sts); hostdata->queued--; + + if (Cmnd->use_sg) + pci64_unmap_sg(hostdata->pci_dev, + (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + else if (Cmnd->request_bufflen) + pci64_unmap_single(hostdata->pci_dev, *(dma64_addr_t *)&Cmnd->SCp, + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + /* * if any of the following are true we do not * call scsi_done. if the status is CS_ABORTED @@ -1550,7 +1564,7 @@ * level should already know its aborted. */ if (hostdata->handle_serials[sts->handle] != Cmnd->serial_number - || sts->completion_status == CS_ABORTED){ + || le16_to_cpu(sts->completion_status) == CS_ABORTED){ hostdata->handle_serials[sts->handle] = 0; hostdata->handle_ptrs[sts->handle] = NULL; outw(out_ptr, host->io_port + MBOX5); @@ -1564,7 +1578,7 @@ * the device may well be back in a couple of * seconds. */ - if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == CS_PORT_UNAVAILABLE || sts->completion_status == CS_PORT_LOGGED_OUT || sts->completion_status == CS_PORT_CONFIG_CHANGED) && hostdata->port_db[Cmnd->target].wwn){ + if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == cpu_to_le16(CS_PORT_UNAVAILABLE) || sts->completion_status == cpu_to_le16(CS_PORT_LOGGED_OUT) || sts->completion_status == cpu_to_le16(CS_PORT_CONFIG_CHANGED)) && hostdata->port_db[Cmnd->target].wwn){ outw(out_ptr, host->io_port + MBOX5); continue; } @@ -1575,12 +1589,11 @@ hostdata->handle_ptrs[sts->handle] = NULL; - if (sts->completion_status == CS_RESET_OCCURRED - || (sts->status_flags & STF_BUS_RESET)) + if (sts->completion_status == cpu_to_le16(CS_RESET_OCCURRED) + || (sts->status_flags & cpu_to_le16(STF_BUS_RESET))) hostdata->send_marker = 1; - memset(Cmnd->sense_buffer, 0, sizeof(Cmnd->sense_buffer)); - if (sts->scsi_status & 0x0200) + if (le16_to_cpu(sts->scsi_status) & 0x0200) memcpy(Cmnd->sense_buffer, sts->req_sense_data, sizeof(Cmnd->sense_buffer)); @@ -1638,9 +1651,9 @@ ENTER("isp2x00_return_status"); DEBUG(printk("qlogicfc : completion status = 0x%04x\n", - sts->completion_status)); + le16_to_cpu(sts->completion_status))); - switch (sts->completion_status) { + switch (le16_to_cpu(sts->completion_status)) { case CS_COMPLETE: host_status = DID_OK; break; @@ -1660,7 +1673,7 @@ host_status = DID_ERROR; break; case CS_DATA_UNDERRUN: - if (Cmnd->underflow <= (Cmnd->request_bufflen - sts->residual)) + if (Cmnd->underflow <= (Cmnd->request_bufflen - le32_to_cpu(sts->residual))) host_status = DID_OK; else host_status = DID_ERROR; @@ -1675,17 +1688,17 @@ break; default: printk("qlogicfc : unknown completion status 0x%04x\n", - sts->completion_status); + le16_to_cpu(sts->completion_status)); host_status = DID_ERROR; break; } DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n", - reason[host_status], sts->scsi_status)); + reason[host_status], le16_to_cpu(sts->scsi_status))); LEAVE("isp2x00_return_status"); - return (sts->scsi_status & STATUS_MASK) | (host_status << 16); + return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16); } @@ -1802,6 +1815,7 @@ u_short param[8]; struct isp2x00_hostdata *hostdata; int loop_count; + dma64_addr_t busaddr; ENTER("isp2x00_reset_hardware"); @@ -1896,6 +1910,14 @@ } #endif +#ifdef __BIG_ENDIAN + { + u64 val; + memcpy(&val, &hostdata->control_block.node_name, sizeof(u64)); + hostdata->wwn = ((val & 0xff00ff00ff00ff00ULL) >> 8) + | ((val & 0x00ff00ff00ff00ffULL) << 8); + } +#else hostdata->wwn = (u64) (hostdata->control_block.node_name[0]) << 56; hostdata->wwn |= (u64) (hostdata->control_block.node_name[0] & 0xff00) << 48; hostdata->wwn |= (u64) (hostdata->control_block.node_name[1] & 0xff00) << 24; @@ -1904,26 +1926,37 @@ hostdata->wwn |= (u64) (hostdata->control_block.node_name[2] & 0xff00) << 8; hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0x00ff) << 8; hostdata->wwn |= (u64) (hostdata->control_block.node_name[3] & 0xff00) >> 8; +#endif + + /* FIXME: If the DMA transfer goes one way only, this should use PCI_DMA_TODEVICE and below as well. */ + busaddr = pci64_map_single(hostdata->pci_dev, &hostdata->control_block, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); param[0] = MBOX_INIT_FIRMWARE; - param[2] = (u_short) (virt_to_bus_low32(&hostdata->control_block) >> 16); - param[3] = (u_short) (virt_to_bus_low32(&hostdata->control_block) & 0xffff); + param[2] = (u_short) (pci64_dma_lo32(busaddr) >> 16); + param[3] = (u_short) (pci64_dma_lo32(busaddr) & 0xffff); param[4] = 0; param[5] = 0; - param[6] = (u_short) (virt_to_bus_high32(&hostdata->control_block) >> 16); - param[7] = (u_short) (virt_to_bus_high32(&hostdata->control_block) & 0xffff); + param[6] = (u_short) (pci64_dma_hi32(busaddr) >> 16); + param[7] = (u_short) (pci64_dma_hi32(busaddr) & 0xffff); isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id, param[0]); + pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); return 1; } param[0] = MBOX_GET_FIRMWARE_STATE; isp2x00_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id, param[0]); + pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); return 1; } + pci64_unmap_single(hostdata->pci_dev, busaddr, sizeof(hostdata->control_block), + PCI_DMA_BIDIRECTIONAL); LEAVE("isp2x00_reset_hardware"); return 0; @@ -1939,11 +1972,11 @@ return 1; value = isp2x00_read_nvram_word(host, 8); - control_block->node_name[0] = isp2x00_read_nvram_word(host, 9); - control_block->node_name[1] = isp2x00_read_nvram_word(host, 10); - control_block->node_name[2] = isp2x00_read_nvram_word(host, 11); - control_block->node_name[3] = isp2x00_read_nvram_word(host, 12); - control_block->hard_addr = isp2x00_read_nvram_word(host, 13); + control_block->node_name[0] = cpu_to_le16(isp2x00_read_nvram_word(host, 9)); + control_block->node_name[1] = cpu_to_le16(isp2x00_read_nvram_word(host, 10)); + control_block->node_name[2] = cpu_to_le16(isp2x00_read_nvram_word(host, 11)); + control_block->node_name[3] = cpu_to_le16(isp2x00_read_nvram_word(host, 12)); + control_block->hard_addr = cpu_to_le16(isp2x00_read_nvram_word(host, 13)); return 0; @@ -2156,12 +2189,12 @@ printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n", - status->scsi_status, status->completion_status); + le16_to_cpu(status->scsi_status), le16_to_cpu(status->completion_status)); printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", - status->state_flags, status->status_flags); + le16_to_cpu(status->state_flags), le16_to_cpu(status->status_flags)); printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n", - status->res_info_len, status->req_sense_len); - printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", status->residual, status->res_info[3]); + le16_to_cpu(status->res_info_len), le16_to_cpu(status->req_sense_len)); + printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", le32_to_cpu(status->residual), status->res_info[3]); } diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/qlogicfc.h linux/drivers/scsi/qlogicfc.h --- v2.3.47/linux/drivers/scsi/qlogicfc.h Thu Nov 18 20:25:37 1999 +++ linux/drivers/scsi/qlogicfc.h Wed Feb 23 13:37:35 2000 @@ -62,7 +62,7 @@ * determined for each queue request anew. */ -#if BITS_PER_LONG > 32 +#if PCI64_DMA_BITS > 32 #define DATASEGS_PER_COMMAND 2 #define DATASEGS_PER_CONT 5 #else diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/sgiwd93.c linux/drivers/scsi/sgiwd93.c --- v2.3.47/linux/drivers/scsi/sgiwd93.c Wed Dec 8 14:11:26 1999 +++ linux/drivers/scsi/sgiwd93.c Thu Feb 24 22:51:47 2000 @@ -2,10 +2,12 @@ * sgiwd93.c: SGI WD93 scsi driver. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) - * + * 1999 Andrew R. Baker (andrewb@uab.edu) + * - Support for 2nd SCSI controller on Indigo2 + * * (In all truth, Jed Schimmel wrote all this code.) * - * $Id: sgiwd93.c,v 1.13 1999/03/28 23:06:06 tsbogend Exp $ + * $Id: sgiwd93.c,v 1.20 2000/02/21 15:05:48 ralf Exp $ */ #include #include @@ -13,16 +15,16 @@ #include #include #include +#include #include #include -#include #include -#include -#include -#include +#include +#include +#include +#include #include -#include #include #include "scsi.h" @@ -38,6 +40,7 @@ }; 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) @@ -65,7 +68,7 @@ unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); - wd33c93_intr(sgiwd93_host); + wd33c93_intr((struct Scsi_Host *) dev_id); spin_unlock_irqrestore(&io_request_lock, flags); } @@ -231,9 +234,9 @@ #endif } -void sgiwd93_reset(void) +void sgiwd93_reset(uchar *base) { - struct hpc3_scsiregs *hregs = &hpc3c0->scsi_chan0; + struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) base; hregs->ctrl = HPC3_SCTRL_CRESET; udelay (50); @@ -261,9 +264,11 @@ { static unsigned char called = 0; struct hpc3_scsiregs *hregs = &hpc3c0->scsi_chan0; + struct hpc3_scsiregs *hregs1 = &hpc3c0->scsi_chan1; struct WD33C93_hostdata *hdata; + struct WD33C93_hostdata *hdata1; uchar *buf; - + if(called) return 0; /* Should bitch on the console about this... */ @@ -271,12 +276,12 @@ sgiwd93_host = scsi_register(SGIblows, sizeof(struct WD33C93_hostdata)); sgiwd93_host->base = (unsigned char *) hregs; - sgiwd93_host->irq = 1; + sgiwd93_host->irq = SGI_WD93_0_IRQ; buf = (uchar *) get_free_page(GFP_KERNEL); init_hpc_chain(buf); dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); - + /* HPC_SCSI_REG0 | 0x03 | KSEG1 */ wd33c93_init(sgiwd93_host, (wd33c93_regs *) 0xbfbc0003, dma_setup, dma_stop, WD33C93_FS_16_20); @@ -285,7 +290,28 @@ hdata->dma_bounce_buffer = (uchar *) (KSEG1ADDR(buf)); dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); - request_irq(1, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host); + request_irq(SGI_WD93_0_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host); + /* set up second controller on the Indigo2 */ + if(!sgi_guiness) { + sgiwd93_host1 = scsi_register(SGIblows, sizeof(struct WD33C93_hostdata)); + sgiwd93_host1->base = (unsigned char *) hregs1; + sgiwd93_host1->irq = SGI_WD93_1_IRQ; + + buf = (uchar *) get_free_page(GFP_KERNEL); + init_hpc_chain(buf); + dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE); + /* HPC_SCSI_REG1 | 0x03 | KSEG1 */ + wd33c93_init(sgiwd93_host1, (wd33c93_regs *) 0xbfbc8003, + 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); + + request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1); + } + called = 1; return 1; /* Found one. */ @@ -306,9 +332,14 @@ int sgiwd93_release(struct Scsi_Host *instance) { #ifdef MODULE - free_irq(1, sgiwd93_intr); + free_irq(SGI_WD93_0_IRQ, sgiwd93_intr); free_page(KSEG0ADDR(hdata->dma_bounce_buffer)); wd33c93_release(); + if(!sgi_guiness) { + free_irq(SGI_WD93_1_IRQ, sgiwd93_intr); + free_page(KSEG0ADDR(hdata1->dma_bounce_buffer)); + wd33c93_release(); + } #endif return 1; } diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/sgiwd93.h linux/drivers/scsi/sgiwd93.h --- v2.3.47/linux/drivers/scsi/sgiwd93.h Thu Nov 11 20:11:48 1999 +++ linux/drivers/scsi/sgiwd93.h Thu Feb 24 22:51:47 2000 @@ -1,4 +1,4 @@ -/* $Id: sgiwd93.h,v 1.5 1998/08/25 09:18:50 ralf Exp $ +/* $Id: sgiwd93.h,v 1.6 2000/01/29 01:42:18 ralf Exp $ * sgiwd93.h: SGI WD93 scsi definitions. * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v2.3.47/linux/drivers/scsi/sr_ioctl.c Sun Feb 20 21:12:39 2000 +++ linux/drivers/scsi/sr_ioctl.c Tue Feb 22 22:19:07 2000 @@ -149,7 +149,7 @@ sr_cmd[0] = GPCMD_TEST_UNIT_READY; sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; - return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1, SCSI_DATA_NONE); + return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE); } int sr_tray_move(struct cdrom_device_info *cdi, int pos) @@ -161,7 +161,7 @@ sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; - return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0, SCSI_DATA_NONE); + return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE); } int sr_lock_door(struct cdrom_device_info *cdi, int lock) diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/sun3_scsi.c linux/drivers/scsi/sun3_scsi.c --- v2.3.47/linux/drivers/scsi/sun3_scsi.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/scsi/sun3_scsi.c Sat Feb 26 20:33:03 2000 @@ -121,10 +121,6 @@ /* minimum number of bytes to to dma on */ #define SUN3_DMA_MINSIZE 128 -static struct proc_dir_entry proc_scsi_sun3_5380 = { - PROC_SCSI_MAC, 13, "Sun3 5380 SCSI", S_IFDIR | S_IRUGO, S_IXUGO, 2 -}; - static volatile unsigned char *sun3_scsi_regp; static volatile struct sun3_dma_regs *dregs; static unsigned char *dmabuf = NULL; /* dma memory buffer */ @@ -196,7 +192,7 @@ if(called) return 0; - tpnt->proc_dir = &proc_scsi_sun3_5380; + tpnt->proc_name = "Sun3 5380 SCSI"; /* setup variables */ tpnt->can_queue = diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c --- v2.3.47/linux/drivers/scsi/sym53c8xx.c Tue Jan 11 22:31:41 2000 +++ linux/drivers/scsi/sym53c8xx.c Mon Feb 21 17:35:06 2000 @@ -55,7 +55,7 @@ */ /* -** January 9 2000, sym53c8xx 1.5h +** February 20 2000, sym53c8xx 1.5j ** ** Supported SCSI features: ** Synchronous data transfers @@ -84,7 +84,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5h" +#define SCSI_NCR_DRIVER_NAME "sym53c8xx - version 1.5j" /* #define DEBUG_896R1 */ #define SCSI_NCR_OPTIMIZE_896 @@ -174,6 +174,15 @@ #include "sym53c8xx.h" +/* +** Hmmm... What complex some PCI-HOST bridges actually are, +** despite the fact that the PCI specifications are looking +** so smart and simple! ;-) +*/ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,47) +#define SCSI_NCR_DYNAMIC_DMA_MAPPING +#endif + /*========================================================== ** ** A la VMS/CAM-3 queue management. @@ -501,7 +510,7 @@ typedef unsigned int pcidev_t; #define PCIDEV_NULL (~0u) #define PciBusNumber(d) ((d)>>8) -#define PciDeviceFn(n) ((d)&0xff) +#define PciDeviceFn(d) ((d)&0xff) #define __PciDev(busn, devfn) (((busn)<<8)+(devfn)) #define pci_present pcibios_present @@ -539,7 +548,7 @@ static u_short __init PciVendorId(pcidev_t dev) { u_short vendor_id; - pcibios_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); + pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id); return vendor_id; } @@ -552,7 +561,7 @@ static u_int __init PciIrqLine(pcidev_t dev) { - u_short irq; + u_char irq; pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); return irq; } @@ -652,17 +661,6 @@ #endif /* -** Address translation -** -** The driver has to provide bus memory addresses to -** the script processor. Because some architectures use -** different physical addressing scheme from the PCI BUS, -** we use virt_to_bus() instead of virt_to_phys(). -*/ - -#define vtobus(p) virt_to_bus(p) - -/* ** Memory mapped IO ** ** Since linux-2.1, we must use ioremap() to map the io memory space. @@ -736,44 +734,76 @@ ** this allocator allows simple and fast address calculations ** from the SCRIPTS code. In addition, cache line alignment ** is guaranteed for power of 2 cache line size. +** Enhanced in linux-2.3.44 to provide a memory pool per pcidev +** to support dynamic dma mapping. (I would have preferred a +** real bus astraction, btw). */ -#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ -#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum (for now (ever?) */ -typedef unsigned long addr; /* Enough bits to bit-hack addresses */ - -#define MEMO_FREE_UNUSED /* Free unused pages immediately */ - -struct m_link { - struct m_link *next; /* Simple links are enough */ -}; - -#ifndef GFP_DMA_32BIT -#define GFP_DMA_32BIT 0 /* Will this flag ever exist */ -#endif - #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) -#define GetPages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order) +#define __GetFreePages(flags, order) __get_free_pages(flags, order) #else -#define GetPages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order, 0) +#define __GetFreePages(flags, order) __get_free_pages(flags, order, 0) #endif -/* -** Lists of available memory chunks. -** Starts with 16 bytes chunks until 1 PAGE chunks. -*/ -static struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1]; +#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ +#if PAGE_SIZE >= 8192 +#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */ +#else +#define MEMO_PAGE_ORDER 1 /* 2 PAGES maximum */ +#endif +#define MEMO_FREE_UNUSED /* Free unused pages immediately */ +#define MEMO_WARN 1 +#define MEMO_GFP_FLAGS GFP_ATOMIC +#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER) +#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT) +#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1) + +typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */ +typedef pcidev_t m_bush_t; /* Something that addresses DMAable */ + +typedef struct m_link { /* Link between free memory chunks */ + struct m_link *next; +} m_link_s; + +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING +typedef struct m_vtob { /* Virtual to Bus address translation */ + struct m_vtob *next; + m_addr_t vaddr; + m_addr_t baddr; +} m_vtob_s; +#define VTOB_HASH_SHIFT 5 +#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT) +#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1) +#define VTOB_HASH_CODE(m) \ + ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK) +#endif + +typedef struct m_pool { /* Memory pool of a given kind */ +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + m_bush_t bush; + m_addr_t (*getp)(struct m_pool *); + void (*freep)(struct m_pool *, m_addr_t); +#define M_GETP() mp->getp(mp) +#define M_FREEP(p) mp->freep(mp, p) +#define GetPages() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER) +#define FreePages(p) free_pages(p, MEMO_PAGE_ORDER) + int nump; + m_vtob_s *(vtob[VTOB_HASH_SIZE]); + struct m_pool *next; +#else +#define M_GETP() __GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER) +#define M_FREEP(p) free_pages(p, MEMO_PAGE_ORDER) +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1]; +} m_pool_s; -/* -** Allocate a memory area aligned on the lowest power of 2 -** greater than the requested size. -*/ -static void *__m_alloc(int size) +static void *___m_alloc(m_pool_s *mp, int size) { int i = 0; int s = (1 << MEMO_SHIFT); int j; - addr a ; + m_addr_t a; + m_link_s *h = mp->h; if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) return 0; @@ -786,7 +816,7 @@ j = i; while (!h[j].next) { if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { - h[j].next = (struct m_link *) GetPages(MEMO_PAGE_ORDER); + h[j].next = (m_link_s *) M_GETP(); if (h[j].next) h[j].next->next = 0; break; @@ -794,36 +824,32 @@ ++j; s <<= 1; } - a = (addr) h[j].next; + a = (m_addr_t) h[j].next; if (a) { h[j].next = h[j].next->next; while (j > i) { j -= 1; s >>= 1; - h[j].next = (struct m_link *) (a+s); + h[j].next = (m_link_s *) (a+s); h[j].next->next = 0; } } #ifdef DEBUG - printk("m_alloc(%d) = %p\n", size, (void *) a); + printk("___m_alloc(%d) = %p\n", size, (void *) a); #endif return (void *) a; } -/* -** Free a memory area allocated using m_alloc(). -** Coalesce buddies. -** Free pages that become unused if MEMO_FREE_UNUSED is defined. -*/ -static void __m_free(void *ptr, int size) +static void ___m_free(m_pool_s *mp, void *ptr, int size) { int i = 0; int s = (1 << MEMO_SHIFT); - struct m_link *q; - addr a, b; + m_link_s *q; + m_addr_t a, b; + m_link_s *h = mp->h; #ifdef DEBUG - printk("m_free(%p, %d)\n", ptr, size); + printk("___m_free(%p, %d)\n", ptr, size); #endif if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) @@ -834,23 +860,23 @@ ++i; } - a = (addr) ptr; + a = (m_addr_t) ptr; while (1) { #ifdef MEMO_FREE_UNUSED if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { - free_pages(a, MEMO_PAGE_ORDER); + M_FREEP(a); break; } #endif b = a ^ s; q = &h[i]; - while (q->next && q->next != (struct m_link *) b) { + while (q->next && q->next != (m_link_s *) b) { q = q->next; } if (!q->next) { - ((struct m_link *) a)->next = h[i].next; - h[i].next = (struct m_link *) a; + ((m_link_s *) a)->next = h[i].next; + h[i].next = (m_link_s *) a; break; } q->next = q->next->next; @@ -860,45 +886,338 @@ } } -#define MEMO_WARN 1 - -/* -** The memory pool is shared by all instances. -** We use a global SMP LOCK to be SMP safe. -*/ - -static void *m_calloc(int size, char *name, int uflags) +static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags) { - u_long flags; void *p; - NCR_LOCK_DRIVER(flags); - p = __m_alloc(size); - NCR_UNLOCK_DRIVER(flags); + p = ___m_alloc(mp, size); if (DEBUG_FLAGS & DEBUG_ALLOC) printk ("new %-10s[%4d] @%p.\n", name, size, p); if (p) - memset(p, 0, size); + bzero(p, size); else if (uflags & MEMO_WARN) printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size); return p; } +#define __m_calloc(mp, s, n) __m_calloc2(mp, s, n, MEMO_WARN) + +static void __m_free(m_pool_s *mp, void *ptr, int size, char *name) +{ + if (DEBUG_FLAGS & DEBUG_ALLOC) + printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr); + + ___m_free(mp, ptr, size); + +} + +/* + * With pci bus iommu support, we use a default pool of unmapped memory + * for memory we donnot need to DMA from/to and one pool per pcidev for + * memory accessed by the PCI chip. `mp0' is the default not DMAable pool. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +static m_pool_s mp0; + +#else + +static m_addr_t ___mp0_getp(m_pool_s *mp) +{ + m_addr_t m = GetPages(); + if (m) + ++mp->nump; + return m; +} + +static void ___mp0_freep(m_pool_s *mp, m_addr_t m) +{ + FreePages(m); + --mp->nump; +} + +static m_pool_s mp0 = {0, ___mp0_getp, ___mp0_freep}; + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +static void *m_calloc(int size, char *name) +{ + u_long flags; + void *m; + NCR_LOCK_DRIVER(flags); + m = __m_calloc(&mp0, size, name); + NCR_UNLOCK_DRIVER(flags); + return m; +} + static void m_free(void *ptr, int size, char *name) { u_long flags; + NCR_LOCK_DRIVER(flags); + __m_free(&mp0, ptr, size, name); + NCR_UNLOCK_DRIVER(flags); +} - if (DEBUG_FLAGS & DEBUG_ALLOC) - printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr); +/* + * DMAable pools. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +/* Without pci bus iommu support, all the memory is assumed DMAable */ + +#define __m_calloc_dma(b, s, n) m_calloc(s, n) +#define __m_free_dma(b, p, s, n) m_free(p, s, n) +#define __vtobus(b, p) virt_to_bus(p) + +#else + +/* + * With pci bus iommu support, we maintain one pool per pcidev and a + * hashed reverse table for virtual to bus physical address translations. + */ +static m_addr_t ___dma_getp(m_pool_s *mp) +{ + m_addr_t vp; + m_vtob_s *vbp; + + vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB"); + if (vbp) { + dma_addr_t daddr; + vp = (m_addr_t) pci_alloc_consistent(mp->bush, + PAGE_SIZE<vaddr = vp; + vbp->baddr = daddr; + vbp->next = mp->vtob[hc]; + mp->vtob[hc] = vbp; + ++mp->nump; + return vp; + } + } + __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); + return 0; +} + +static void ___dma_freep(m_pool_s *mp, m_addr_t m) +{ + m_vtob_s **vbpp, *vbp; + int hc = VTOB_HASH_CODE(m); + + vbpp = &mp->vtob[hc]; + while (*vbpp && (*vbpp)->vaddr != m) + vbpp = &(*vbpp)->next; + if (*vbpp) { + vbp = *vbpp; + *vbpp = (*vbpp)->next; + pci_free_consistent(mp->bush, PAGE_SIZE<vaddr, (dma_addr_t)vbp->baddr); + __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); + --mp->nump; + } +} + +static inline m_pool_s *___get_dma_pool(m_bush_t bush) +{ + m_pool_s *mp; + for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next); + return mp; +} + +static m_pool_s *___cre_dma_pool(m_bush_t bush) +{ + m_pool_s *mp; + mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL"); + if (mp) { + bzero(mp, sizeof(*mp)); + mp->bush = bush; + mp->getp = ___dma_getp; + mp->freep = ___dma_freep; + mp->next = mp0.next; + mp0.next = mp; + } + return mp; +} + +static void ___del_dma_pool(m_pool_s *p) +{ + struct m_pool **pp = &mp0.next; + + while (*pp && *pp != p) + pp = &(*pp)->next; + if (*pp) { + *pp = (*pp)->next; + __m_free(&mp0, p, sizeof(*p), "MPOOL"); + } +} + +static void *__m_calloc_dma(m_bush_t bush, int size, char *name) +{ + u_long flags; + struct m_pool *mp; + void *m = 0; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (!mp) + mp = ___cre_dma_pool(bush); + if (mp) + m = __m_calloc(mp, size, name); + if (mp && !mp->nump) + ___del_dma_pool(mp); + NCR_UNLOCK_DRIVER(flags); + + return m; +} + +static void __m_free_dma(m_bush_t bush, void *m, int size, char *name) +{ + u_long flags; + struct m_pool *mp; + + NCR_LOCK_DRIVER(flags); + mp = ___get_dma_pool(bush); + if (mp) + __m_free(mp, m, size, name); + if (mp && !mp->nump) + ___del_dma_pool(mp); + NCR_UNLOCK_DRIVER(flags); +} + +static m_addr_t __vtobus(m_bush_t bush, void *m) +{ + u_long flags; + m_pool_s *mp; + int hc = VTOB_HASH_CODE(m); + m_vtob_s *vp = 0; + m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK; NCR_LOCK_DRIVER(flags); - __m_free(ptr, size); + mp = ___get_dma_pool(bush); + if (mp) { + vp = mp->vtob[hc]; + while (vp && (m_addr_t) vp->vaddr != a) + vp = vp->next; + } NCR_UNLOCK_DRIVER(flags); + return vp ? vp->baddr + (((m_addr_t) m) - a) : 0; +} + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->pdev, s, n) +#define _m_free_dma(np, p, s, n) __m_free_dma(np->pdev, p, s, n) +#define m_calloc_dma(s, n) _m_calloc_dma(np, s, n) +#define m_free_dma(p, s, n) _m_free_dma(np, p, s, n) +#define _vtobus(np, p) __vtobus(np->pdev, p) +#define vtobus(p) _vtobus(np, p) + +/* + * Deal with DMA mapping/unmapping. + */ + +#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING + +/* Linux versions prior to pci bus iommu kernel interface */ + +#define __unmap_scsi_data(pdev, cmd) do {; } while (0) +#define __map_scsi_single_data(pdev, cmd) (__vtobus(pdev,(cmd)->request_buffer)) +#define __map_scsi_sg_data(pdev, cmd) ((cmd)->use_sg) +#define __sync_scsi_data(pdev, cmd) do {; } while (0) + +#define scsi_sg_dma_address(sc) vtobus((sc)->address) +#define scsi_sg_dma_len(sc) ((sc)->length) + +#else + +/* Linux version with pci bus iommu kernel interface */ + +/* To keep track of the dma mapping (sg/single) that has been set */ +#define __data_mapped SCp.phase +#define __data_mapping SCp.have_data_in + +static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(cmd->__data_mapped) { + case 2: + pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_unmap_single(pdev, cmd->__data_mapping, + cmd->request_bufflen, dma_dir); + break; + } + cmd->__data_mapped = 0; +} + +static u_long __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + dma_addr_t mapping; + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + if (cmd->request_bufflen == 0) + return 0; + + mapping = pci_map_single(pdev, cmd->request_buffer, + cmd->request_bufflen, dma_dir); + cmd->__data_mapped = 1; + cmd->__data_mapping = mapping; + + return mapping; } +static int __map_scsi_sg_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int use_sg; + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + if (cmd->use_sg == 0) + return 0; + + use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + cmd->__data_mapped = 2; + cmd->__data_mapping = use_sg; + + return use_sg; +} + +static void __sync_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(cmd->__data_mapped) { + case 2: + pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_dma_sync_single(pdev, cmd->__data_mapping, + cmd->request_bufflen, dma_dir); + break; + } +} + +#define scsi_sg_dma_address(sc) sg_dma_address(sc) +#define scsi_sg_dma_len(sc) sg_dma_len(sc) + +#endif /* SCSI_NCR_DYNAMIC_DMA_MAPPING */ + +#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->pdev, cmd) +#define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->pdev, cmd) +#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->pdev, cmd) +#define sync_scsi_data(np, cmd) __sync_scsi_data(np->pdev, cmd) + + +/* + * Print out some buffer. + */ static void ncr_print_hex(u_char *p, int n) { while (n-- > 0) @@ -915,21 +1234,49 @@ /* ** Transfer direction ** -** Low-level scsi drivers under Linux do not receive the expected -** data transfer direction from upper scsi drivers. -** The driver will only check actual data direction for common -** scsi opcodes. Other ones may cause problem, since they may -** depend on device type or be vendor specific. -** I would prefer to never trust the device for data direction, -** but that is not possible. -** -** The original driver requires the expected direction to be known. -** The Linux version of the driver has been enhanced in order to -** be able to transfer data in the direction choosen by the target. +** Until some linux kernel version near 2.3.40, low-level scsi +** drivers were not told about data transfer direction. +** We check the existence of this feature that has been expected +** for a _long_ time by all SCSI driver developers by just +** testing against the definition of SCSI_DATA_UNKNOWN. Indeed +** this is a hack, but testing against a kernel version would +** have been a shame. ;-) */ +#ifdef SCSI_DATA_UNKNOWN + +#define scsi_data_direction(cmd) (cmd->sc_data_direction) -#define XFER_IN (1) -#define XFER_OUT (2) +#else + +#define SCSI_DATA_UNKNOWN 0 +#define SCSI_DATA_WRITE 1 +#define SCSI_DATA_READ 2 +#define SCSI_DATA_NONE 3 + +static __inline__ scsi_data_direction(Scsi_Cmnd *cmd) +{ + int direction; + + switch((int) cmd->cmnd[0]) { + case 0x08: /* READ(6) 08 */ + case 0x28: /* READ(10) 28 */ + case 0xA8: /* READ(12) A8 */ + direction = SCSI_DATA_READ; + break; + case 0x0A: /* WRITE(6) 0A */ + case 0x2A: /* WRITE(10) 2A */ + case 0xAA: /* WRITE(12) AA */ + direction = SCSI_DATA_WRITE; + break; + default: + direction = SCSI_DATA_UNKNOWN; + break; + } + + return direction; +} + +#endif /* SCSI_DATA_UNKNOWN */ /* ** Head of list of NCR boards @@ -1039,6 +1386,7 @@ ** to save data on each detected board for ncr_attach(). */ typedef struct { + pcidev_t pdev; ncr_slot slot; ncr_chip chip; ncr_nvram *nvram; @@ -1796,6 +2144,8 @@ **---------------------------------------------------------------- */ Scsi_Cmnd *cmd; /* SCSI command */ + u_char cdb_buf[16]; /* Copy of CDB */ + u_char sense_buf[64]; int data_len; /* Total data length */ int segments; /* Number of SG segments */ @@ -1964,6 +2314,7 @@ ** General controller parameters and configuration. **---------------------------------------------------------------- */ + pcidev_t pdev; u_short device_id; /* PCI device id */ u_char revision_id; /* PCI device revision id */ u_char bus; /* PCI BUS number */ @@ -1995,7 +2346,8 @@ ** SCRIPTS processor in order to start SCSI commands. **---------------------------------------------------------------- */ - u_int32 *squeue; /* Start queue */ + u_long p_squeue; /* Start queue BUS address */ + u_int32 *squeue; /* Start queue virtual address */ u_short squeueput; /* Next free slot of the queue */ u_short actccbs; /* Number of allocated CCBs */ u_short queuedepth; /* Start queue depth */ @@ -2045,6 +2397,7 @@ u_char order; /* Tag order to use */ u_char verbose; /* Verbosity for this controller*/ u_int32 ncr_cache; /* Used for cache test at init. */ + u_long p_ncb; /* BUS address of this NCB */ /*---------------------------------------------------------------- ** CCB lists and queue. @@ -2085,7 +2438,7 @@ ** We use a different scatter function for 896 rev 1. **---------------------------------------------------------------- */ - int (*scatter) (ccb_p, Scsi_Cmnd *); + int (*scatter) (ncb_p, ccb_p, Scsi_Cmnd *); /*---------------------------------------------------------------- ** Command abort handling. @@ -2106,6 +2459,7 @@ u_char release_stage; /* Synchronisation stage on release */ }; +#define NCB_PHYS(np, lbl) (np->p_ncb + offsetof(struct ncb, lbl)) #define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) #define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl)) #define NCB_SCRIPTH0_PHYS(np,lbl) (np->p_scripth0+offsetof (struct scripth,lbl)) @@ -2336,8 +2690,8 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len); static void ncr_script_fill (struct script * scr, struct scripth * scripth); -static int ncr_scatter_896R1 (ccb_p cp, Scsi_Cmnd *cmd); -static int ncr_scatter (ccb_p cp, Scsi_Cmnd *cmd); +static int ncr_scatter_896R1 (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); +static int ncr_scatter (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd); static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p); static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer); static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln); @@ -4529,7 +4883,7 @@ new = (old & ~RELOC_MASK) + np->p_scripth; break; case RELOC_SOFTC: - new = (old & ~RELOC_MASK) + vtobus(np); + new = (old & ~RELOC_MASK) + np->p_ncb; break; #ifdef RELOC_KVAR case RELOC_KVAR: @@ -5191,10 +5545,12 @@ /* ** Allocate the host control block. */ - np = m_calloc(sizeof(struct ncb), "NCB", MEMO_WARN); + np = __m_calloc_dma(device->pdev, sizeof(struct ncb), "NCB"); if (!np) goto attach_error; NCR_INIT_LOCK_NCB(np); + np->pdev = device->pdev; + np->p_ncb = __vtobus(device->pdev, np); host_data->ncb = np; /* @@ -5218,22 +5574,23 @@ ** Allocate the start queue. */ np->squeue = (ncrcmd *) - m_calloc(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE", MEMO_WARN); + m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); if (!np->squeue) goto attach_error; + np->p_squeue = vtobus(np->squeue); /* ** Allocate the done queue. */ np->dqueue = (ncrcmd *) - m_calloc(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE", MEMO_WARN); + m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE"); if (!np->dqueue) goto attach_error; /* ** Allocate the target bus address array. */ - np->targtbl = (u_int32 *) m_calloc(256, "TARGTBL", MEMO_WARN); + np->targtbl = (u_int32 *) m_calloc_dma(256, "TARGTBL"); if (!np->targtbl) goto attach_error; @@ -5241,11 +5598,11 @@ ** Allocate SCRIPTS areas */ np->script0 = (struct script *) - m_calloc(sizeof(struct script), "SCRIPT", MEMO_WARN); + m_calloc_dma(sizeof(struct script), "SCRIPT"); if (!np->script0) goto attach_error; np->scripth0 = (struct scripth *) - m_calloc(sizeof(struct scripth), "SCRIPTH", MEMO_WARN); + m_calloc_dma(sizeof(struct scripth), "SCRIPTH"); if (!np->scripth0) goto attach_error; @@ -5457,24 +5814,24 @@ */ np->idletask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->idletask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); - np->p_idletask = vtobus(&np->idletask); + np->p_idletask = NCB_PHYS(np, idletask); np->notask.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->notask.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); - np->p_notask = vtobus(&np->notask); + np->p_notask = NCB_PHYS(np, notask); np->bad_i_t_l.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->bad_i_t_l.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l)); - np->p_bad_i_t_l = vtobus(&np->bad_i_t_l); + np->p_bad_i_t_l = NCB_PHYS(np, bad_i_t_l); np->bad_i_t_l_q.start = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); np->bad_i_t_l_q.restart = cpu_to_scr(NCB_SCRIPTH_PHYS (np,bad_i_t_l_q)); - np->p_bad_i_t_l_q = vtobus(&np->bad_i_t_l_q); + np->p_bad_i_t_l_q = NCB_PHYS(np, bad_i_t_l_q); /* ** Allocate and prepare the bad lun table. */ - np->badluntbl = m_calloc(256, "BADLUNTBL", MEMO_WARN); + np->badluntbl = m_calloc_dma(256, "BADLUNTBL"); if (!np->badluntbl) goto attach_error; @@ -5482,16 +5839,16 @@ np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_identify)); for (i = 0 ; i < 64 ; i++) - np->badluntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun)); + np->badluntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); /* ** Prepare the target bus address array. */ np->scripth0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl)); for (i = 0 ; i < MAX_TARGET ; i++) { - np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i])); + np->targtbl[i] = cpu_to_scr(NCB_PHYS(np, target[i])); np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl)); - np->target[i].b_lun0 = cpu_to_scr(vtobus(&np->resel_badlun)); + np->target[i].b_lun0 = cpu_to_scr(NCB_PHYS(np, resel_badlun)); } /* @@ -5533,7 +5890,7 @@ #ifndef SCSI_NCR_PROFILE_SUPPORT #define XXX 0 #else -#define XXX 3 +#define XXX 2 #endif np->script0->dataphase[XXX] = cpu_to_scr(SCR_JUMP); np->script0->dataphase[XXX+1] = @@ -5699,21 +6056,21 @@ unmap_pci_mem(np->base2_va, np->base2_ws); #endif if (np->scripth0) - m_free(np->scripth0, sizeof(struct scripth), "SCRIPTH"); + m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH"); if (np->script0) - m_free(np->script0, sizeof(struct script), "SCRIPT"); + m_free_dma(np->script0, sizeof(struct script), "SCRIPT"); if (np->squeue) - m_free(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); + m_free_dma(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE"); if (np->dqueue) - m_free(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE"); + m_free_dma(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE"); while ((cp = np->ccbc) != NULL) { np->ccbc = cp->link_ccb; - m_free(cp, sizeof(*cp), "CCB"); + m_free_dma(cp, sizeof(*cp), "CCB"); } if (np->badluntbl) - m_free(np->badluntbl, 256,"BADLUNTBL"); + m_free_dma(np->badluntbl, 256,"BADLUNTBL"); for (target = 0; target < MAX_TARGET ; target++) { tp = &np->target[target]; @@ -5722,18 +6079,23 @@ if (!lp) continue; if (lp->tasktbl != &lp->tasktbl_0) - m_free(lp->tasktbl, MAX_TASKS*4, "TASKTBL"); + m_free_dma(lp->tasktbl, MAX_TASKS*4, "TASKTBL"); if (lp->cb_tags) m_free(lp->cb_tags, MAX_TAGS, "CB_TAGS"); - m_free(lp, sizeof(*lp), "LCB"); + m_free_dma(lp, sizeof(*lp), "LCB"); } #if MAX_LUN > 1 if (tp->lmp) m_free(tp->lmp, MAX_LUN * sizeof(lcb_p), "LMP"); + if (tp->luntbl) + m_free_dma(tp->luntbl, 256, "LUNTBL"); #endif } - m_free(np, sizeof(*np), "NCB"); + if (np->targtbl) + m_free_dma(np->targtbl, 256, "TARGTBL"); + + m_free_dma(np, sizeof(*np), "NCB"); } @@ -5761,13 +6123,14 @@ np->done_list = cmd; } -static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd) +static inline void ncr_flush_done_cmds(pcidev_t pdev, Scsi_Cmnd *lcmd) { Scsi_Cmnd *cmd; while (lcmd) { cmd = lcmd; lcmd = (Scsi_Cmnd *) cmd->host_scribble; + __unmap_scsi_data(pdev, cmd); cmd->scsi_done(cmd); } } @@ -6013,7 +6376,7 @@ **---------------------------------------------------- */ - cp->segments = segments = np->scatter (cp, cp->cmd); + cp->segments = segments = np->scatter (np, cp, cp->cmd); if (segments < 0) { ncr_free_ccb(np, cp); @@ -6027,61 +6390,34 @@ **---------------------------------------------------- */ if (!cp->data_len) - direction = 0; - else { - switch((int) cmd->cmnd[0]) { - case 0x08: /* READ(6) 08 */ - case 0x28: /* READ(10) 28 */ - case 0xA8: /* READ(12) A8 */ - direction = XFER_IN; - break; - case 0x0A: /* WRITE(6) 0A */ - case 0x2A: /* WRITE(10) 2A */ - case 0xAA: /* WRITE(12) AA */ - direction = XFER_OUT; - break; - default: - direction = (XFER_IN|XFER_OUT); - break; - } - } - - /*---------------------------------------------------- - ** - ** Set the DATA POINTER. - ** - **---------------------------------------------------- - */ - - /* - ** Default to no data transfer. - */ - lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data); + direction = SCSI_DATA_NONE; + else + direction = scsi_data_direction(cmd); /* - ** Compute data out pointers, if needed. + ** If data direction is UNKNOWN, speculate DATA_READ + ** but prepare alternate pointers for WRITE in case + ** of our speculation will be just wrong. + ** SCRIPTS will swap values if needed. */ - if (direction & XFER_OUT) { + switch(direction) { + case SCSI_DATA_UNKNOWN: + case SCSI_DATA_WRITE: goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8; lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4)); - - /* - ** If actual data direction is unknown, save pointers - ** in header. The SCRIPTS will swap them to current - ** if target decision will be data out. - */ - if (direction & XFER_IN) { - cp->phys.header.wgoalp = cpu_to_scr(goalp); - cp->phys.header.wlastp = cpu_to_scr(lastp); - } - } - - /* - ** Compute data in pointers, if needed. - */ - if (direction & XFER_IN) { + if (direction != SCSI_DATA_UNKNOWN) + break; + cp->phys.header.wgoalp = cpu_to_scr(goalp); + cp->phys.header.wlastp = cpu_to_scr(lastp); + /* fall through */ + case SCSI_DATA_READ: goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8; lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4)); + break; + default: + case SCSI_DATA_NONE: + lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data); + break; } /* @@ -6091,7 +6427,7 @@ cp->phys.header.lastp = cpu_to_scr(lastp); cp->phys.header.goalp = cpu_to_scr(goalp); - if ((direction & (XFER_IN|XFER_OUT)) == (XFER_IN|XFER_OUT)) + if (direction == SCSI_DATA_UNKNOWN) cp->phys.header.savep = cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io)); else @@ -6152,7 +6488,8 @@ /* ** command */ - cp->phys.cmd.addr = cpu_to_scr(vtobus (&cmd->cmnd[0])); + memcpy(cp->cdb_buf, cmd->cmnd, cmd->cmd_len); + cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0])); cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len); /* @@ -6719,6 +7056,7 @@ */ if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && cmd->cmnd[4] >= 7 && !cmd->use_sg) { + sync_scsi_data(np, cmd); /* SYNC the data */ ncr_setup_lcb (np, cp->target, cp->lun, (char *) cmd->request_buffer); } @@ -6941,7 +7279,7 @@ /* ** Clear Start Queue */ - phys = vtobus(np->squeue); + phys = np->p_squeue; np->queuedepth = MAX_START - 1; /* 1 entry needed as end marker */ for (i = 0; i < MAX_START*2; i += 2) { np->squeue[i] = cpu_to_scr(np->p_idletask); @@ -7131,7 +7469,7 @@ np->istat_sem = 0; - OUTL (nc_dsa, vtobus(np)); + OUTL (nc_dsa, np->p_ncb); OUTL (nc_dsp, phys); } @@ -8733,7 +9071,7 @@ ** them back in the LUN CCB wait queue. */ busyccbs = lp->queuedccbs; - i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4; + i = (INL (nc_scratcha) - np->p_squeue) / 4; j = i; while (i != np->squeueput) { cp2 = ncr_ccb_from_dsa(np, scr_to_cpu(np->squeue[i])); @@ -8888,11 +9226,9 @@ /* ** sense data */ - bzero(cmd->sense_buffer, sizeof(cmd->sense_buffer)); - cp->phys.sense.addr = - cpu_to_scr(vtobus (&cmd->sense_buffer[0])); - cp->phys.sense.size = - cpu_to_scr(sizeof(cmd->sense_buffer)); + bzero(cp->sense_buf, sizeof(cp->sense_buf)); + cp->phys.sense.addr = cpu_to_scr(CCB_PHYS(cp,sense_buf[0])); + cp->phys.sense.size = cpu_to_scr(sizeof(cp->sense_buf)); /* ** requeue the command. @@ -9073,7 +9409,7 @@ np->abrt_sel.sel_id = target; np->abrt_sel.sel_scntl3 = tp->wval; np->abrt_sel.sel_sxfer = tp->sval; - OUTL(nc_dsa, vtobus(np)); + OUTL(nc_dsa, np->p_ncb); OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort)); return; } @@ -9114,7 +9450,7 @@ ** Compute index of next position in the start ** queue the SCRIPTS will schedule. */ - i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4; + i = (INL (nc_scratcha) - np->p_squeue) / 4; /* ** Remove the job from the start queue. @@ -9315,11 +9651,17 @@ */ case SIR_AUTO_SENSE_DONE: cp = ncr_ccb_from_dsa(np, INL (nc_dsa)); + if (!cp) + break; + memcpy(cp->cmd->sense_buffer, cp->sense_buf, + sizeof(cp->cmd->sense_buffer)); p = &cp->cmd->sense_buffer[0]; if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29) break; +#if 0 (void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1); +#endif break; } @@ -10036,6 +10378,7 @@ case SIR_SCRIPT_STOPPED: case SIR_TARGET_SELECTED: case SIR_ABORT_SENT: + case SIR_AUTO_SENSE_DONE: ncr_sir_task_recovery(np, num); return; /* @@ -10397,7 +10740,7 @@ /* ** Allocate memory for this CCB. */ - cp = m_calloc(sizeof(struct ccb), "CCB", MEMO_WARN); + cp = m_calloc_dma(sizeof(struct ccb), "CCB"); if (!cp) return 0; @@ -10427,7 +10770,7 @@ /* ** Initilialyze some other fields. */ - cp->phys.smsg_ext.addr = cpu_to_scr(vtobus(&np->msgin[2])); + cp->phys.smsg_ext.addr = cpu_to_scr(NCB_PHYS(np, msgin[2])); /* ** Chain into wakeup list and free ccb queue. @@ -10519,11 +10862,11 @@ if (ln && !tp->luntbl) { int i; - tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN); + tp->luntbl = m_calloc_dma(256, "LUNTBL"); if (!tp->luntbl) goto fail; for (i = 0 ; i < 64 ; i++) - tp->luntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun)); + tp->luntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun)); tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl)); } @@ -10531,7 +10874,7 @@ ** Allocate the table of pointers for LUN(s) > 0, if needed. */ if (ln && !tp->lmp) { - tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP", MEMO_WARN); + tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP"); if (!tp->lmp) goto fail; } @@ -10540,7 +10883,7 @@ ** Allocate the lcb. ** Make it available to the chip. */ - lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN); + lp = m_calloc_dma(sizeof(struct lcb), "LCB"); if (!lp) goto fail; if (ln) { @@ -10652,7 +10995,7 @@ ** initialyze the task table if not yet. */ if ((inq_byte7 & INQ7_QUEUE) && lp->tasktbl == &lp->tasktbl_0) { - lp->tasktbl = m_calloc(MAX_TASKS*4, "TASKTBL", MEMO_WARN); + lp->tasktbl = m_calloc_dma(MAX_TASKS*4, "TASKTBL"); if (!lp->tasktbl) { lp->tasktbl = &lp->tasktbl_0; goto fail; @@ -10661,7 +11004,7 @@ for (i = 0 ; i < MAX_TASKS ; i++) lp->tasktbl[i] = cpu_to_scr(np->p_notask); - lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS", MEMO_WARN); + lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS"); if (!lp->cb_tags) goto fail; for (i = 0 ; i < MAX_TAGS ; i++) @@ -10741,7 +11084,7 @@ #define CROSS_16MB(p, n) (((((u_long) p) + n - 1) ^ ((u_long) p)) & ~0xffffff) -static int ncr_scatter_no_sglist(ccb_p cp, Scsi_Cmnd *cmd) +static int ncr_scatter_no_sglist(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) { struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER-1]; int segment; @@ -10749,7 +11092,8 @@ cp->data_len = cmd->request_bufflen; if (cmd->request_bufflen) { - u_long baddr = vtobus(cmd->request_buffer); + u_long baddr = map_scsi_single_data(np, cmd); + SCATTER_ONE(data, baddr, cmd->request_bufflen); if (CROSS_16MB(baddr, cmd->request_bufflen)) { cp->host_flags |= HF_PM_TO_C; @@ -10780,7 +11124,7 @@ ** nicely power-of-two sized and aligned. But, since this may change ** at any time, a work-around was required. */ -static int ncr_scatter_896R1(ccb_p cp, Scsi_Cmnd *cmd) +static int ncr_scatter_896R1(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) { int segn; int use_sg = (int) cmd->use_sg; @@ -10788,18 +11132,23 @@ cp->data_len = 0; if (!use_sg) - segn = ncr_scatter_no_sglist(cp, cmd); + segn = ncr_scatter_no_sglist(np, cp, cmd); else if (use_sg > MAX_SCATTER) segn = -1; else { struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; - struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg]; + struct scr_tblmove *data; + + use_sg = map_scsi_sg_data(np, cmd); + data = &cp->phys.data[MAX_SCATTER - use_sg]; for (segn = 0; segn < use_sg; segn++) { - u_long baddr = vtobus(scatter[segn].address); + u_long baddr = scsi_sg_dma_address(&scatter[segn]); + unsigned int len = scsi_sg_dma_len(&scatter[segn]); + SCATTER_ONE(&data[segn], baddr, - scatter[segn].length); + len); if (CROSS_16MB(baddr, scatter[segn].length)) { cp->host_flags |= HF_PM_TO_C; #ifdef DEBUG_896R1 @@ -10807,14 +11156,14 @@ baddr, scatter[segn].length); #endif } - cp->data_len += scatter[segn].length; + cp->data_len += len; } } return segn; } -static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) +static int ncr_scatter(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd) { int segment; int use_sg = (int) cmd->use_sg; @@ -10822,19 +11171,24 @@ cp->data_len = 0; if (!use_sg) - segment = ncr_scatter_no_sglist(cp, cmd); + segment = ncr_scatter_no_sglist(np, cp, cmd); else if (use_sg > MAX_SCATTER) segment = -1; else { struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; - struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg]; + struct scr_tblmove *data; + + use_sg = map_scsi_sg_data(np, cmd); + data = &cp->phys.data[MAX_SCATTER - use_sg]; for (segment = 0; segment < use_sg; segment++) { - u_long baddr = vtobus(scatter[segment].address); + u_long baddr = scsi_sg_dma_address(&scatter[segment]); + unsigned int len = scsi_sg_dma_len(&scatter[segment]); + SCATTER_ONE(&data[segment], baddr, - scatter[segment].length); - cp->data_len += scatter[segment].length; + len); + cp->data_len += len; } } @@ -10901,7 +11255,7 @@ /* ** Start script (exchange values) */ - OUTL (nc_dsa, vtobus(np)); + OUTL (nc_dsa, np->p_ncb); OUTL (nc_dsp, pc); /* ** Wait 'til done (with timeout) @@ -11580,7 +11934,7 @@ ** overflow the kernel stack. ** 1 x 4K PAGE is enough for more than 40 devices for i386. */ - devtbl = m_calloc(PAGE_SIZE, "devtbl", MEMO_WARN); + devtbl = m_calloc(PAGE_SIZE, "devtbl"); if (!devtbl) return 0; @@ -11745,6 +12099,15 @@ PciBusNumber(pdev), (int) (PciDeviceFn(pdev) & 0xf8) >> 3, (int) (PciDeviceFn(pdev) & 7)); + +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) { + printk(KERN_WARNING NAME53C8XX + "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n"); + return -1; + } +#endif + /* ** Read info from the PCI config space. ** pci_read_config_xxx() functions are assumed to be used for @@ -12032,6 +12395,7 @@ /* ** Initialise ncr_device structure with items required by ncr_attach. */ + device->pdev = pdev; device->slot.bus = PciBusNumber(pdev); device->slot.device_fn = PciDeviceFn(pdev); device->slot.base = base; @@ -12232,6 +12596,10 @@ cmd->host_scribble = NULL; cmd->SCp.ptr = NULL; cmd->SCp.buffer = NULL; +#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING + cmd->__data_mapped = 0; + cmd->__data_mapping = 0; +#endif NCR_LOCK_NCB(np, flags); @@ -12267,6 +12635,7 @@ unsigned long flags; ncb_p np = (ncb_p) dev_id; Scsi_Cmnd *done_list; + pcidev_t pdev; #ifdef DEBUG_SYM53C8XX printk("sym53c8xx : interrupt received\n"); @@ -12276,6 +12645,7 @@ NCR_LOCK_NCB(np, flags); ncr_exception(np); + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); @@ -12284,7 +12654,7 @@ if (done_list) { NCR_LOCK_SCSI_DONE(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); NCR_UNLOCK_SCSI_DONE(np, flags); } } @@ -12297,17 +12667,19 @@ { ncb_p np = (ncb_p) npref; unsigned long flags; + pcidev_t pdev; Scsi_Cmnd *done_list; NCR_LOCK_NCB(np, flags); ncr_timeout((ncb_p) np); + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); if (done_list) { NCR_LOCK_SCSI_DONE(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); NCR_UNLOCK_SCSI_DONE(np, flags); } } @@ -12325,6 +12697,7 @@ ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; int sts; unsigned long flags; + pcidev_t pdev; Scsi_Cmnd *done_list; #if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS @@ -12369,11 +12742,12 @@ #endif out: + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); return sts; } @@ -12387,6 +12761,7 @@ ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; int sts; unsigned long flags; + pcidev_t pdev; Scsi_Cmnd *done_list; #if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS @@ -12410,11 +12785,12 @@ sts = ncr_abort_command(np, cmd); out: + pdev = np->pdev; done_list = np->done_list; np->done_list = 0; NCR_UNLOCK_NCB(np, flags); - ncr_flush_done_cmds(done_list); + ncr_flush_done_cmds(pdev, done_list); return sts; } diff -u --recursive --new-file v2.3.47/linux/drivers/scsi/wd33c93.h linux/drivers/scsi/wd33c93.h --- v2.3.47/linux/drivers/scsi/wd33c93.h Tue Nov 23 22:42:21 1999 +++ linux/drivers/scsi/wd33c93.h Thu Feb 24 22:51:47 2000 @@ -191,7 +191,7 @@ typedef struct { volatile unsigned char SASR; char pad; -#ifdef CONFIG_SGI +#ifdef CONFIG_SGI_IP22 char pad2,pad3; #endif volatile unsigned char SCMD; diff -u --recursive --new-file v2.3.47/linux/drivers/sgi/Config.in linux/drivers/sgi/Config.in --- v2.3.47/linux/drivers/sgi/Config.in Fri Oct 15 15:25:14 1999 +++ linux/drivers/sgi/Config.in Thu Feb 24 22:51:08 2000 @@ -5,14 +5,10 @@ comment 'SGI devices' bool 'SGI Zilog85C30 serial support' CONFIG_SGI_SERIAL -if [ "$CONFIG_SGI_SERIAL" != "n" ]; then - define_bool CONFIG_SERIAL y -fi - bool 'SGI DS1286 RTC support' CONFIG_SGI_DS1286 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'SGI Newport Graphics support (EXPERIMENTAL)' CONFIG_SGI_NEWPORT_GFX + tristate 'SGI Newport Graphics support' CONFIG_SGI_NEWPORT_GFX fi endmenu diff -u --recursive --new-file v2.3.47/linux/drivers/sgi/char/ds1286.c linux/drivers/sgi/char/ds1286.c --- v2.3.47/linux/drivers/sgi/char/ds1286.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/sgi/char/ds1286.c Thu Feb 24 22:51:08 2000 @@ -1,4 +1,4 @@ -/* $Id: ds1286.c,v 1.4 1999/06/17 13:29:03 ralf Exp $ +/* $Id: ds1286.c,v 1.7 2000/02/23 00:41:21 ralf Exp $ * * Real Time Clock interface for Linux * @@ -73,9 +73,7 @@ static inline unsigned char ds1286_is_updating(void); -#ifdef __SMP__ static spinlock_t ds1286_lock = SPIN_LOCK_UNLOCKED; -#endif /* * Bits in rtc_status. (7 bits of room for future expansion) diff -u --recursive --new-file v2.3.47/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c --- v2.3.47/linux/drivers/sgi/char/graphics.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/sgi/char/graphics.c Thu Feb 24 22:51:08 2000 @@ -1,4 +1,4 @@ -/* $Id: graphics.c,v 1.16 1999/04/01 23:45:00 ulfc Exp $ +/* $Id: graphics.c,v 1.23 2000/02/23 00:41:21 ralf Exp $ * * gfx.c: support for SGI's /dev/graphics, /dev/opengl * @@ -41,7 +41,7 @@ #include #include #include -#include +#include