diff -u --recursive --new-file v2.4.1/linux/CREDITS linux/CREDITS --- v2.4.1/linux/CREDITS Sat Feb 3 19:51:21 2001 +++ linux/CREDITS Fri Feb 16 17:15:23 2001 @@ -62,6 +62,15 @@ S: B-2610 Wilrijk-Antwerpen S: Belgium +N: Anton Altaparmakov +E: aia21@cus.cam.ac.uk +W: http://www-stu.christs.cam.ac.uk/~aia21/ +D: NTFS driver maintainer. NTFS fixes and cleanup. +D: Tiny fixes in linear md device and emu10k1 driver. +S: Christ's College +S: Cambridge CB2 3BU +S: United Kingdom + N: C. Scott Ananian E: cananian@alumni.princeton.edu W: http://www.pdos.lcs.mit.edu/~cananian @@ -83,6 +92,14 @@ S: Salt Lake City, Utah 84120 S: USA +N: Michael Ang +E: mang@subcarrier.org +W: http://www.subcarrier.org/mang +D: Linux/PA-RISC hacker +S: 85 Frank St. +S: Ottawa, Ontario +S: Canada K2P 0X3 + N: H. Peter Anvin E: hpa@zytor.com W: http://www.zytor.com/~hpa/ @@ -161,6 +178,17 @@ S: Milano S: Italy +N: Paul Bame +E: bame@debian.org +E: bame@puffin.external.hp.com +E: paul_bame@hp.com +W: http://www.parisc-linux.org +D: PA-RISC 32 and 64-bit early boot, firmware interface, interrupts, misc +S: MS42 +S: Hewlett-Packard +S: 3404 E Harmony Rd +S: Fort Collins, CO 80525 + N: Arindam Banerji E: axb@cse.nd.edu D: Contributed ESDI driver routines needed to port LINUX to the PS/2 MCA. @@ -375,6 +403,12 @@ S: Pittsburgh, Pennsylvania 15213 S: USA +N: Ryan Bradetich +E: rbradetich@uswest.net +D: Linux/PA-RISC hacker +S: 1200 Goldenrod Dr. +S: Nampa, Idaho 83686 + N: Derrick J. Brashear E: shadow@dementia.org W: http://www.dementia.org/~shadow @@ -606,6 +640,14 @@ D: AX25-HOWTO, HAM-HOWTO, IPX-HOWTO, NET-2-HOWTO D: ax25-utils maintainer. +N: Helge Deller +E: deller@gmx.de +E: hdeller@redhat.de +D: PA-RISC Linux hacker, LASI-, ASP-, WAX-, LCD/LED-driver +S: Schimmelsrain 1 +S: D-69231 Rauenberg +S: Germany + N: Peter Denison E: peterd@pnd-pc.demon.co.uk W: http://www.pnd-pc.demon.co.uk/promise/ @@ -957,11 +999,22 @@ N: Hans Grobler E: grobh@sun.ac.za D: Various AX.25/ROSE/NETROM + hamradio driver patches +D: Various X.25/LABP + driver patches +D: Misc kernel fixes and updates S: Department of Electronic Engineering S: University of Stellenbosch S: Stellenbosch, Western Cape S: South Africa +N: Grant Grundler +E: grundler@puffin.external.hp.com +W: http://www.grundler.net/ +W: http://obmouse.sourceforge.net/ +D: obmouse - rewrote Olivier Florent's Omnibook 600 "pop-up" mouse driver +D: PA-RISC - IO Interrupt/PCI HBA/IO MMU author and architect +S: Mountain View, California +S: USA + N: Grant Guenther E: grant@torque.net W: http://www.torque.net/linux-pp.html @@ -1051,11 +1104,12 @@ N: Jochen Hein E: jochen@jochen.org P: 1024/4A27F015 25 72 FB E3 85 9F DE 3B CB 0A DA DA 40 77 05 6C +P: 1024D/77D4FC9B F5C5 1C20 1DFC DEC3 3107 54A4 2332 ADFC 77D4 FC9B D: National Language Support D: Linux Internationalization Project D: German Localization for Linux and GNU software -S: Frankenstrae 33 -S: 34131 Kassel +S: Helenenstrasse 18 +S: 65183 Wiesbaden S: Germany N: Christoph Hellwig @@ -1106,6 +1160,15 @@ S: D - 72072 Tuebingen S: Germany +N: Richard Hirst +E: richard@sleepie.demon.co.uk +E: rhirst@linuxcare.com +W: http://www.sleepie.demon.co.uk/ +D: linux-m68k VME support +D: PA-RISC port, scsi and network drivers +D: 53c700/53c710 driver author, 82596 driver maintainer +S: United Kingdom + N: Jauder Ho E: jauderho@carumba.com W: http://www.carumba.com/ @@ -1182,6 +1245,19 @@ S: Tabor 390 03 S: Czech Republic +N: David Huggins-Daines +E: dhd@debian.org +E: dhd@eradicator.org +E: dhd@cepstral.com +D: PA-RISC port +D: Nubus subsystem +D: Generic 68k Macintosh framebuffer driver +D: STI framebuffer tweaks +D: LTPC driver tweaks +S: 110 S. 12th St., Apt. A +S: Pittsburgh, PA 15203-1250 +S: USA + N: Gareth Hughes E: gareth@valinux.com E: gareth@precisioninsight.com @@ -1250,11 +1326,7 @@ N: Niels Kristian Bech Jensen E: nkbj@image.dk W: http://www.image.dk/~nkbj -D: 4.4BSD and NeXTstep filesystem support in the old ufs. -D: Openstep filesystem and NeXTstep CDROM support in the new ufs. -D: Replace CPU==[3-6]86 and __i386__ submodel flags by configuration options. -D: Replace __SMP__ by CONFIG_SMP. -D: Danish HOWTO, Linux+FreeBSD mini-HOWTO. +D: Miscellaneous kernel updates and fixes. S: Dr. Holsts Vej 34, lejl. 164 S: DK-8230 byhj S: Denmark @@ -1736,6 +1808,14 @@ D: XF86_8514 D: cfdisk (curses based disk partitioning program) +N: John S. Marvin +E: jsm@fc.hp.com +D: PA-RISC port +S: Hewlett Packard +S: MS 42 +S: 3404 E. Harmony Road +S: Fort Collins, CO 80528 + N: Torben Mathiasen E: torben.mathiasen@compaq.com E: torben@kernel.dk @@ -2086,6 +2166,16 @@ D: implemented kmod D: modularized BSD Unix domain sockets +N: Martin Kasper Petersen +E: mkp@linuxcare.com +E: mkp@mkp.net +D: PA-RISC port +D: XFS file system +D: kiobuf based block I/O work +S: 314 Frank St. +S: Ottawa, Ontario +S: Canada K2P 0X8 + N: Mikael Pettersson E: mikpe@csd.uu.se W: http://www.csd.uu.se/~mikpe/ @@ -2270,6 +2360,13 @@ S: D-68789 St.Leon-Rot S: Germany +N: Thiago Berlitz Rondon +E: maluco@mileniumnet.com.br +D: Miscellaneous kernel hacker +S: R. Anhanguera, 1487 - Ipiranga +S: 79080-740 - Campo Grande - Mato Grosso do Sul +S: Brazil + N: Stephen Rothwell E: sfr@linuxcare.com.au W: http://linuxcare.com.au/sfr @@ -2597,7 +2694,7 @@ S: Austria N: Jeff Tranter -E: Jeff_Tranter@Mitel.COM +E: tranter@pobox.com D: Enhancements to Joystick driver D: Author of Sound HOWTO and CD-ROM HOWTO D: Author of several small utilities @@ -2871,6 +2968,12 @@ S: 2135 CN Hoofddorp S: The Netherlands +N: Matthew Wilcox +E: matthew@wil.cx +W: ftp://ftp.uk.linux.org/pub/linux/people/willy/ +D: Linux/PARISC hacker. Filesystem hacker. Random other hacking. Custom +D: PPC port hacking. + N: G\"unter Windau E: gunter@mbfys.kun.nl D: Some bug fixes in the polling printer driver (lp.c) @@ -2931,9 +3034,10 @@ D: some Alpha platform porting from 2.0, Memory Technology Devices, D: Acquire watchdog timer, PC speaker driver maintenance, D: various other stuff that annoyed me by not working. -S: c/o Red Hat UK Limited -S: 35-36 Cambridge Place -S: Cambridge. CB2 1NS +S: c/o Red Hat Engineering +S: Rustat House +S: 60 Clifton Road +S: Cambridge. CB1 7EG S: England N: Frank Xia @@ -2955,8 +3059,8 @@ W: http://www.andante.org D: General kernel hacker D: SCSI iso9660 and ELF -S: 17 Canterbury Square #101 -S: Alexandria, Virginia 22304 +S: 6389 Hawk View Lane +S: Alexandria, Virginia 22312 S: USA N: Niibe Yutaka diff -u --recursive --new-file v2.4.1/linux/Documentation/00-INDEX linux/Documentation/00-INDEX --- v2.4.1/linux/Documentation/00-INDEX Tue Nov 14 10:54:07 2000 +++ linux/Documentation/00-INDEX Thu Feb 8 16:32:44 2001 @@ -1,8 +1,8 @@ + This is a brief list of all the files in ./linux/Documentation and what they contain. If you add a documentation file, please list it here in alphabetical order as well, or risk being hunted down like a rabid dog. -Note that subdirectories have their own index files too. Please try and -keep the descriptions small enough to fit on one line. +Please try and keep the descriptions small enough to fit on one line. Thanks -- Paul G. 00-INDEX @@ -15,28 +15,40 @@ - how the boss likes the C code in the kernel to look. Configure.help - text file that is used for help when you run "make config" -IO-APIC.txt - - info on using the enhanced interrupt hardware on SMP boards. +DMA-mapping.txt + - info for PCI drivers using DMA portably across all platforms. +DocBook/ + - directory with DocBook templates etc. for kernel documentation. IO-mapping.txt - how to access I/O mapped memory from within device drivers. +IRQ-affinity.txt + - how to select which CPU(s) handle which interrupt events on SMP. +LVM-HOWTO + - info on setting up logical volume management (virtual disks etc.) README.DAC960 - info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux +README.moxa + - release notes for Moxa mutiport serial card. +SubmittingDrivers + - procedure to get a new driver source included into the kernel tree. +SubmittingPatches + - procedure to get a source patch included into the kernel tree. VGA-softcursor.txt - how to change your VGA cursor from a blinking underscore. arm/ - directory with info about Linux on the ARM architecture. -atm.txt - - info on Linux ATM support binfmt_misc.txt - info on the kernel support for extra binary formats. +cachetlb.txt + - describes the cache/TLB flushing interfaces Linux uses. +cciss.txt + - info, major/minor #'s for Compaq's SMART Array Controllers. cdrom/ - directory with information on the CD-ROM drivers that Linux has. computone.txt - info on Computone Intelliport II/Plus Multiport Serial Driver cpqarray.txt - info on using Compaq's SMART2 Intelligent Disk Array Controllers. -devices.tex - - LaTeX source listing of all the nodes in /dev/ with major minor #'s devices.txt - plain ASCII listing of all the nodes in /dev/ with major minor #'s digiboard.txt @@ -51,12 +63,20 @@ - directory with info on the frame buffer graphics abstraction layer. filesystems/ - directory with info on the various filesystems that Linux supports. +floppy.txt + - notes and driver options for the floppy disk driver. ftape.txt - notes about the floppy tape device driver hayes-esp.txt - info on using the Hayes ESP serial driver. +highuid.txt + - notes on the change from 16 bit to 32 bit user/group IDs. +i2c/ + - directory with info about the I2C bus/protocol (2 wire, kHz speed) i386/ - - directory with info about Linux on the intel ix86 architecture. + - directory with info about Linux on intel 32 bit architecture. +ia64/ + - directory with info about Linux on intel 64 bit architecture. ide.txt - important info for users of ATA devices (IDE/EIDE disks and CD-ROMS) initrd.txt @@ -77,6 +97,8 @@ - info on using joystick devices (and driver) with Linux. kbuild/ - directory with info about the kernel build process +kernel-doc-nano-HOWTO.txt + - mini HowTo on generation and location of kernel documentation files. kernel-docs.txt - listing of various WWW + books that document kernel internals. kernel-parameters.txt @@ -101,10 +123,14 @@ - info on boot arguments for the multiple devices driver memory.txt - info on typical Linux memory problems. +mkdev.cciss + - script to make /dev entries for SMART controllers (see cciss.txt) mkdev.ida - script to make /dev entries for Intelligent Disk Array Controllers. modules.txt - short guide on how to make kernel parts into loadable modules +moxa-smartio + - info on installing/using Moxa multiport serial driver. mtrr.txt - how to use PPro Memory Type Range Registers to increase performance nbd.txt @@ -119,8 +145,12 @@ - how to decode those nasty internal kernel error dump messages. paride.txt - information about the parallel port IDE subsystem. +parisc/ + - directory with info on using Linux on PA-RISC architecture. parport.txt - how to use the parallel-port driver. +parport-lowlevel.txt + - description and usage of the low level parallel port functions. pci.txt - info on the PCI subsystem for device driver authors pcwd-watchdog.txt @@ -129,14 +159,14 @@ - info on Linux power management support powerpc/ - directory with info on using Linux with the PowerPC. -proc_usb_info.txt - - info on /proc/bus/usb direcory generated for USB devices ramdisk.txt - short guide on how to set up and use the RAM disk. riscom8.txt - notes on using the RISCom/8 multi-port serial driver. rtc.txt - notes on how to use the Real Time Clock (aka CMOS clock) driver. +s390/ + - directory with info on using Linux on the IBM S390. scsi-generic.txt - info on the sg driver for generic (non-disk/CD/tape) SCSI devices. scsi.txt @@ -153,6 +183,8 @@ - a few more notes on symmetric multi-processing sound/ - directory with info on sound card support +sparc/ + - directory with info on using Linux on Sparc architecture. specialix.txt - info on hardware/driver for specialix IO8+ multiport serial card. spinlocks.txt @@ -167,8 +199,12 @@ - directory with info on the /proc/sys/* files sysrq.txt - info on the magic SysRq key +telephony/ + - directory with info on telephony (e.g. voice over IP) support. unicode.txt - info on the Unicode character/font mapping used in Linux. +usb/ + - directory with info regarding the Universal Serial Bus. video4linux/ - directory with info regarding video/TV/radio cards and linux. vm/ @@ -177,4 +213,6 @@ - how to auto-reboot Linux if it has "fallen and can't get up". ;-) xterm-linux.xpm - XPM image of penguin logo (see logo.txt) sitting on an xterm. +zorro.txt + - info on writing drivers for Zorro bus devices found on Amigas. diff -u --recursive --new-file v2.4.1/linux/Documentation/Changes linux/Documentation/Changes --- v2.4.1/linux/Documentation/Changes Sat Feb 3 19:51:21 2001 +++ linux/Documentation/Changes Fri Feb 16 15:53:08 2001 @@ -31,7 +31,7 @@ Eine deutsche Version dieser Datei finden Sie unter . -Last updated: December 11, 2000 +Last updated: January 11, 2001 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu). @@ -52,8 +52,9 @@ o Gnu make 3.77 # make --version o binutils 2.9.1.0.25 # ld -v o util-linux 2.10o # fdformat --version -o modutils 2.4.0 # insmod -V -o e2fsprogs 1.19 # tune2fs --version +o modutils 2.4.2 # insmod -V +o e2fsprogs 1.19 # tune2fs +o reiserfsprogs 3.x.0b # reiserfsck 2>&1|grep reiserfsprogs o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version @@ -99,11 +100,11 @@ your kernel. This change does, however, mean that you need a recent release of binutils. -If you can, upgrade to the latest 2.9.5 binutils release. Older +If you can, upgrade to the latest 2.9.5 or 2.10 binutils release. Older releases such as 2.8, 2.8.xx, and the FSF's 2.9.1 should be avoided if at all possible. The later releases of 2.9.1.0.x (anything where x >= 22) -can and do compile the kernel properly, but there are many benefits -to upgrading to 2.9.5 if you're up to it. +can and do compile the kernel properly, but there are many benefits in +upgrading to 2.9.5 or 2.10 if you're up to it. System utils ============ @@ -114,20 +115,6 @@ DevFS is now in the kernel. See Documentation/filesystems/devfs/* in the kernel source tree for all the gory details. -System V shared memory is now implemented via a virtual filesystem. -You do not have to mount it to use it. SYSV shared memory limits are -set via /proc/sys/kernel/shm{max,all,mni}. You should mount the -filesystem under /dev/shm to be able to use POSIX shared -memory. Adding the following line to /etc/fstab should take care of -things: - -none /dev/shm shm defaults 0 0 - -Remember to create the directory that you intend to mount shm on if -necessary (The entry is automagically created if you use devfs). You -can set limits for the number of blocks and inodes used by the -filesystem with the mount options nr_blocks and nr_inodes. - The Logical Volume Manager (LVM) is now in the kernel. If you want to use this, you'll need to install the necessary LVM toolset. @@ -178,6 +165,14 @@ The latest version of e2fsprogs fixes several bugs in fsck and debugfs. Obviously, it's a good idea to upgrade. +Reiserfsprogs +------------- + +The reiserfsprogs package should be used for reiserfs-3.6.x +(Linux kernels 2.4.x). It is a combined package and contains working +versions of mkreiserfs, resize_reiserfs, debugreiserfs and +reiserfsck. These utils work on both i386 and alpha platforms. + Pcmcia-cs --------- @@ -206,6 +201,14 @@ to your /etc/modules.conf file. +Powertweak +---------- + +If you are running v0.1.17 or earlier, you should upgrade to +version v0.99.0 or higher. Running old versions may cause problems +with programs using shared memory. + + Networking ========== @@ -262,10 +265,19 @@ ********* egcs 1.1.2 (gcc 2.91.66) ---------- -o -o -o +------------------------ +o + +gcc 2.95.2 +---------- +o + +Gnu Make +******** + +Make 3.77 +-------- +o Binutils ******** @@ -274,20 +286,20 @@ ------------ o -2.10 series ------------- -o +2.9.5 and 2.10 series +--------------------- +o System utilities **************** Util-linux ---------- -o +o Ksymoops -------- -o +o Modutils -------- @@ -295,13 +307,17 @@ Mkinitrd -------- -o +o E2fsprogs --------- o o +Reiserfsprogs +------------- +o + LVM toolset ----------- o @@ -322,6 +338,10 @@ ------------------ o +Powertweak +---------- +o + Network ******* @@ -331,7 +351,7 @@ Isdn4k-utils ------------ -o +o Netfilter --------- diff -u --recursive --new-file v2.4.1/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.1/linux/Documentation/Configure.help Sat Feb 3 19:51:21 2001 +++ linux/Documentation/Configure.help Mon Feb 19 10:18:18 2001 @@ -1,7 +1,7 @@ # Maintained by Axel Boldt (axel@uni-paderborn.de) # # This version of the Linux kernel configuration help texts -# corresponds to the kernel versions 2.3.x. +# corresponds to the kernel versions 2.4.x. # # Translations of this file available on the WWW: # @@ -1575,16 +1575,6 @@ more details about the Baget see the Linux/MIPS FAQ on http://oss.sgi.com/mips . -Support for Cobalt Microserver -CONFIG_COBALT_MICRO_SERVER - This enables support for the Cobalt Microserver. For more information - see the Linux/MIPS FAQ on http://oss.sgi.com/mips . - -Support for 2800 -CONFIG_COBALT_28 - This adds support for the Cobalt Microserver 2800. A kernel with this - option selected will only work on the 2800. - Support for DECstations CONFIG_DECSTATION This enables support for DEC's MIPS based workstations. For details @@ -2572,7 +2562,7 @@ inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. You will get modules called i2o_core.o - and i20_config.o. + and i2o_config.o. If unsure, say N. @@ -3104,7 +3094,7 @@ nVidia Riva support (EXPERIMENTAL) CONFIG_FB_RIVA - This driver supports graphics boards with the nVidia Riva (aka TNTx) + This driver supports graphics boards with the nVidia Riva/Geforce chips. Say Y if you have such a graphics board. @@ -5119,7 +5109,7 @@ Compaq Smart Array support CONFIG_BLK_CPQ_CISS_DA - This is the driver for Compaq Smart Array controllers. + This is the driver for Compaq Smart Array 5xxx controllers. Everyone using these boards should say Y here. See Documentation/cciss.txt for the current list of boards supported by this driver, and for further information @@ -10361,14 +10351,12 @@ USB Serial converter support CONFIG_USB_SERIAL Say Y here if you have a USB device that provides normal serial - ports, and you want to connect it to your USB bus. Supported devices - are the Tech WhiteHEAT multi-port USB to serial converter, and the - FTDI or Keyspan single port USB to serial converter Handspring - Visor. In addition to saying Y here, you need to say Y to the driver - for your specific hardware below. Some other devices may also be - used if you say Y to "USB Generic Serial Driver", below. + ports, or acts like a serial device, and you want to connect it to + your USB bus. - Please read Documentation/usb/usb-serial.txt for more information. + Please read Documentation/usb/usb-serial.txt for more information + on the specifics of the different devices that are supported, and + on how to use them. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -10474,6 +10462,10 @@ CONFIG_USB_SERIAL_KEYSPAN_USA19W Say Y here to include firmware for the USA-19W converter. +USB Keyspan USA-49W Firmware +CONFIG_USB_SERIAL_KEYSPAN_USA49W + Say Y here to include firmware for the USA-49W converter. + USB ZyXEL omni.net LCD Plus Driver CONFIG_USB_SERIAL_OMNINET Say Y here if you want to use a ZyXEL omni.net LCD ISDN TA. @@ -10514,6 +10506,9 @@ CONFIG_USB_SERIAL_MCT_U232 Say Y here if you want to use a USB Serial single port adapter from Magic Control Technology Corp. (U232 is one of the model numbers). + + This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB + BAY devices. This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -10523,7 +10518,7 @@ USB Serial Converter verbose debug CONFIG_USB_SERIAL_DEBUG Say Y here if you want verbose debug messages from the USB Serial - Converter. + Drivers sent to the kernel debug log. USB Printer support CONFIG_USB_PRINTER @@ -10798,11 +10793,10 @@ Balanced trees are more efficient than traditional filesystem architectural foundations. - You can use reiserfs in all cases where you use the ext2fs file - system, and you will gain in speed and disk space. It has fewer - worst case performance situations than other file systems - because balanced trees are hardier creatures than other algorithms - are (if that is not technical enough, read www.namesys.com....:-) ) + In general, ReiserFS is as fast as ext2, but is very efficient + with large directories and small files. Additional patches are + needed for NFS and quotas, please see www.reiserfs.org for + links. It is more easily extended to have features currently found in database and keyword search systems than block allocation based @@ -10810,7 +10804,7 @@ support plugins consistent with our motto ``It takes more than a license to make source code open.'' - Read www.namesys.com to learn more about reiserfs. + Read www.reiserfs.org to learn more about reiserfs. Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com. diff -u --recursive --new-file v2.4.1/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.4.1/linux/Documentation/DocBook/Makefile Sat Dec 30 18:16:13 2000 +++ linux/Documentation/DocBook/Makefile Sat Feb 3 12:43:55 2001 @@ -81,6 +81,7 @@ $(TOPDIR)/fs/devfs/base.c \ $(TOPDIR)/kernel/pm.c \ $(TOPDIR)/kernel/ksyms.c \ + $(TOPDIR)/kernel/kmod.c \ $(TOPDIR)/net/netsyms.c kernel-api.sgml: kernel-api.tmpl $(APISOURCES) diff -u --recursive --new-file v2.4.1/linux/Documentation/DocBook/kernel-hacking.tmpl linux/Documentation/DocBook/kernel-hacking.tmpl --- v2.4.1/linux/Documentation/DocBook/kernel-hacking.tmpl Mon Nov 27 17:47:38 2000 +++ linux/Documentation/DocBook/kernel-hacking.tmpl Thu Feb 8 16:32:44 2001 @@ -1179,7 +1179,7 @@ You may well want to make your CONFIG option only visible if CONFIG_EXPERIMENTAL is enabled: this serves as a warning to users. There many other fancy things you can do: see - the the various Config.in files for ideas. + the various Config.in files for ideas. diff -u --recursive --new-file v2.4.1/linux/Documentation/DocBook/kernel-locking.tmpl linux/Documentation/DocBook/kernel-locking.tmpl --- v2.4.1/linux/Documentation/DocBook/kernel-locking.tmpl Fri Dec 29 14:07:19 2000 +++ linux/Documentation/DocBook/kernel-locking.tmpl Fri Feb 16 15:53:08 2001 @@ -386,7 +386,7 @@ spin_lock() and spin_unlock() calls. spin_lock_bh() is - unnecessary here, as you are already in a a tasklet, and + unnecessary here, as you are already in a tasklet, and none will be run on the same CPU. @@ -720,7 +720,8 @@ halves without a lock. Depending on their exact timing, they would either see the new element in the list with a valid next pointer, or it would not be in the - list yet. + list yet. A lock is still required against other CPUs inserting + or deleting from the list, of course. diff -u --recursive --new-file v2.4.1/linux/Documentation/SubmittingDrivers linux/Documentation/SubmittingDrivers --- v2.4.1/linux/Documentation/SubmittingDrivers Sun Dec 3 17:48:18 2000 +++ linux/Documentation/SubmittingDrivers Thu Feb 8 16:32:44 2001 @@ -45,7 +45,7 @@ What Criteria Determine Acceptance ---------------------------------- -Licensing: The code must be released to us under the GNU public license. +Licensing: The code must be released to us under the GNU General Public License. We don't insist on any kind of exclusively GPL licensing, and if you wish the driver to be useful to other communities such as BSD you may well wish to release under multiple diff -u --recursive --new-file v2.4.1/linux/Documentation/cciss.txt linux/Documentation/cciss.txt --- v2.4.1/linux/Documentation/cciss.txt Fri Sep 22 17:11:37 2000 +++ linux/Documentation/cciss.txt Sat Feb 3 12:13:19 2001 @@ -6,6 +6,8 @@ This driver is known to work with the following cards: * SA 5300 + * SA 5i + * SA 532 If notes are not already created in the /dev/cciss directory diff -u --recursive --new-file v2.4.1/linux/Documentation/cris/README linux/Documentation/cris/README --- v2.4.1/linux/Documentation/cris/README Wed Dec 31 16:00:00 1969 +++ linux/Documentation/cris/README Thu Feb 8 16:32:44 2001 @@ -0,0 +1,174 @@ +Linux 2.4 on the CRIS architecture +================================== +$Id: README,v 1.5 2001/01/10 17:20:55 bjornw Exp $ + +This is a port of Linux 2.4 to Axis Communications ETRAX 100LX embedded network CPU. For +more information about CRIS and ETRAX please see further below. + +<... to come: instructions on how to grab the right gcc, compiling and booting ...> + + +What is CRIS ? +-------------- + +CRIS is an acronym for 'Code Reduced Instruction Set'. It is the CPU architecture in Axis +Communication AB's range of embedded network CPU's, called ETRAX. The latest CPU is called +ETRAX 100LX, where LX stands for 'Linux' because the chip was designed to be a good host for +the Linux operating system. + +The ETRAX 100LX chip +-------------------- + +For reference, plase see the press-release: + +http://www.axis.com/news/us/001101_etrax.htm + +The ETRAX 100LX is a 100 MIPS processor with 8kB cache, MMU, and a very broad range of +built-in interfaces, all with modern scatter/gather DMA. + +Memory interfaces: + + * SRAM + * NOR-flash/ROM + * EDO or page-mode DRAM + * SDRAM + +I/O interfaces: + + * one 10/100 Mbit/s ethernet controller + * four serial-ports (up to 6 Mbit/s) + * two synchronous serial-ports for multimedia codec's etc. + * USB host controller and USB slave + * ATA + * SCSI + * two parallel-ports + * two generic 8-bit ports + + (not all interfaces are available at the same time due to chip pin multiplexing) + +The previous version of the ETRAX, the ETRAX 100, sits in almost all of Axis shipping +thin-servers like the Axis 2100 web camera or the developer-board. It lacks an MMU so the +Linux we run on that is a version of uClinux (Linux 2.0 without MM-support) ported to the CRIS +architecture. The new Linux 2.4 port has full MM and needs a CPU with an MMU, so it will not +run on the ETRAX 100. + +A version of the Axis developer-board with ETRAX 100LX will be available as soon as the chip +is ramped up (please see http://developer.axis.com for further information on that). + + + +Bootlog +------- + +Just as an example, this is the debug-output from a boot of Linux 2.4 on an Axis +developer-board with ETRAX 100LX. The displayed BogoMIPS value is 5 times too small :) +At the end you see some user-mode programs booting like telnet and ftp daemons. + +Linux version 2.4.0-test11 (bjornw@godzilla.axis.se) (gcc version 2.96 20000427 (experimental)) #358 Wed Nov 22 19:29:15 CET 2000 +ROM fs in RAM, size 368640 bytes +Setting up paging and the MMU. +On node 0 totalpages: 1024 +zone(0): 1024 pages. +zone(1): 0 pages. +zone(2): 0 pages. +Linux/CRIS port (c) 2000 Axis Communications AB +Kernel command line: +Calibrating delay loop... 19.92 BogoMIPS +Memory: 6864k/8192k available (531k kernel code, 1328k reserved, 85k data, 24k init) +kmem_create: Forcing size word alignment - vm_area_struct +kmem_create: Forcing size word alignment - filp +Dentry-cache hash table entries: 1024 (order: 0, 8192 bytes) +Buffer-cache hash table entries: 2048 (order: 0, 8192 bytes) +Page-cache hash table entries: 2048 (order: 0, 8192 bytes) +kmem_create: Forcing size word alignment - kiobuf +kmem_create: Forcing size word alignment - bdev_cache +Inode-cache hash table entries: 1024 (order: 0, 8192 bytes) +kmem_create: Forcing size word alignment - inode_cache +POSIX conformance testing by UNIFIX +Linux NET4.0 for Linux 2.4 +Based upon Swansea University Computer Society NET3.039 +kmem_create: Forcing size word alignment - skbuff_head_cache +Starting kswapd v1.8 +kmem_create: Forcing size word alignment - file lock cache +kmem_create: Forcing size word alignment - blkdev_requests +ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB +eth0 initialized +eth0: changed MAC to 00:40:8C:CD:00:00 +ETRAX 100LX serial-driver $Revision: 1.5 $, (c) 2000 Axis Communications AB +ttyS0 at 0xb0000060 is a builtin UART with DMA +ttyS1 at 0xb0000068 is a builtin UART with DMA +ttyS2 at 0xb0000070 is a builtin UART with DMA +ttyS3 at 0xb0000078 is a builtin UART with DMA +NET4: Linux TCP/IP 1.0 for NET4.0 +IP Protocols: ICMP, UDP, TCP +kmem_create: Forcing size word alignment - ip_dst_cache +IP: routing cache hash table of 1024 buckets, 8Kbytes +TCP: Hash tables configured (established 1024 bind 1024) +NET4: Unix domain sockets 1.0/SMP for Linux NET4.0. +VFS: Mounted root (cramfs filesystem) readonly. +Init starts up... +Setting up eth0 with ip 10.13.9.116 and mac 00:40:8c:18:04:60 +eth0: changed MAC to 00:40:8C:18:04:60 +Setting up lo with ip 127.0.0.1 +Default gateway is 10.13.9.1 +Hostname is bbox1 +Telnetd starting, using port 23. + using /bin/sh as shell. +sftpd[14]: sftpd $Revision: 1.5 $ starting up + + +And here is how some /proc entries look: + +17# cd /proc +17# cat cpuinfo +cpu : ETRAX +cpu revision : 10 +cpu model : ETRAX 100LX +cache size : 8 kB +fpu : no +mmu : yes +ethernet : 10/100 Mbps +token ring : no +scsi : yes +ata : yes +usb : yes +bogomips : 99.84 +17# cat meminfo + total: used: free: shared: buffers: cached: +Mem: 7028736 925696 6103040 114688 0 229376 +Swap: 0 0 0 +MemTotal: 6864 kB +MemFree: 5960 kB +MemShared: 112 kB +Buffers: 0 kB +Cached: 224 kB +Active: 224 kB +Inact_dirty: 0 kB +Inact_clean: 0 kB +Inact_target: 0 kB +HighTotal: 0 kB +HighFree: 0 kB +LowTotal: 6864 kB +LowFree: 5960 kB +SwapTotal: 0 kB +SwapFree: 0 kB +17# ls -l /bin +-rwxr-xr-x 1 342 100 10356 Jan 01 00:00 ifconfig +-rwxr-xr-x 1 342 100 17548 Jan 01 00:00 init +-rwxr-xr-x 1 342 100 9488 Jan 01 00:00 route +-rwxr-xr-x 1 342 100 46036 Jan 01 00:00 sftpd +-rwxr-xr-x 1 342 100 48104 Jan 01 00:00 sh +-rwxr-xr-x 1 342 100 16252 Jan 01 00:00 telnetd + + +(All programs are statically linked to the libc at this point - we have not ported the + shared libraries yet) + + + + + + + + + diff -u --recursive --new-file v2.4.1/linux/Documentation/filesystems/00-INDEX linux/Documentation/filesystems/00-INDEX --- v2.4.1/linux/Documentation/filesystems/00-INDEX Wed Feb 16 15:42:05 2000 +++ linux/Documentation/filesystems/00-INDEX Thu Feb 8 16:32:44 2001 @@ -1,5 +1,7 @@ 00-INDEX - this file (info on some of the filesystems supported by linux). +Locking + - info on locking rules as they pertain to Linux VFS. adfs.txt - info and mount options for the Acorn Advanced Disc Filing System. affs.txt @@ -8,8 +10,12 @@ - info for the SCO UnixWare Boot Filesystem (BFS). coda.txt - description of the CODA filesystem. -devfs +cramfs.txt + - info on the cram filesystem for small storage (ROMs etc) +devfs/ - directory containing devfs documentation. +ext2.txt + - info, mount options and specifications for the Ext2 filesystem. fat_cvf.txt - info on the Compressed Volume Files extension to the FAT filesystem hpfs.txt diff -u --recursive --new-file v2.4.1/linux/Documentation/filesystems/Locking linux/Documentation/filesystems/Locking --- v2.4.1/linux/Documentation/filesystems/Locking Fri Jul 28 12:50:51 2000 +++ linux/Documentation/filesystems/Locking Fri Feb 16 15:53:08 2001 @@ -117,7 +117,7 @@ --------------------------- address_space_operations -------------------------- prototypes: - int (*writepage)(struct file *, struct page *); + int (*writepage)(struct page *); int (*readpage)(struct file *, struct page *); int (*sync_page)(struct page *); int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); @@ -126,8 +126,8 @@ locking rules: All may block BKL PageLocked(page) -writepage: no yes -readpage: no yes +writepage: no yes, unlocks +readpage: no yes, unlocks sync_page: no maybe prepare_write: no yes commit_write: no yes @@ -135,6 +135,7 @@ ->prepare_write(), ->commit_write(), ->sync_page() and ->readpage() may be called from the request handler (/dev/loop). + ->readpage() and ->writepage() unlock the page. ->sync_page() locking rules are not well-defined - usually it is called with lock on page, but that is not guaranteed. Considering the currently existing instances of this method ->sync_page() itself doesn't look @@ -285,26 +286,13 @@ prototypes: void (*open)(struct vm_area_struct*); void (*close)(struct vm_area_struct*); - void (*unmap)(struct vm_area_struct*, unsigned long, size_t); - void (*protect)(struct vm_area_struct*, unsigned long, size_t, unsigned); - int (*sync)(struct vm_area_struct*, unsigned long, size_t, unsigned); struct page *(*nopage)(struct vm_area_struct*, unsigned long, int); - struct page *(*wppage)(struct vm_area_struct*, unsigned long, struct page*); - int (*swapout)(struct page *, struct file *); locking rules: BKL mmap_sem open: no yes close: no yes -sync: no yes -unmap: no yes nopage: no yes -swapout: yes yes -wpppage: (see below) -protect: (see below) - -->wppage() and ->protect() have no instances and nothing calls them; looks like -they must die... ================================================================================ Dubious stuff diff -u --recursive --new-file v2.4.1/linux/Documentation/filesystems/ntfs.txt linux/Documentation/filesystems/ntfs.txt --- v2.4.1/linux/Documentation/filesystems/ntfs.txt Tue May 2 13:46:53 2000 +++ linux/Documentation/filesystems/ntfs.txt Fri Feb 16 15:53:08 2001 @@ -2,18 +2,25 @@ ============= To mount an NTFS volume, use the filesystem type 'ntfs'. The driver -currently works only in read-only mode, with no fault-tolerance -supported. If you enable the experimental write support, make sure -you can recover from a complete loss of data and also always run -chkdsk from within Microsoft Windows NT after performing a write to -a NTFS partition from Linux to detect any problems as early as -possible. For ftdisk support, limited success was reported with -volume sets on top of the md driver, although mirror and stripe -sets should work as well - if the md driver can be talked into -using the same layout as Windows NT. +currently works only in read-only mode, with no fault-tolerance supported. + +If you enable the dangerous(!) write support, make sure you can recover +from a complete loss of data. Also, download the Linux-NTFS project +distribution from Sourceforge at http://sourceforge.net/projects/linux-ntfs/ +and always run the included ntfsfix utility after performing a write to an +NTFS partition from Linux to fix some of the damage done by the Linux NTFS +driver. You should run ntfsfix _after_ unmounting the partition in Linux but +_before_ rebooting into Windows. During the next reboot into Windows, chkdsk +will be run automatically to fix the remaining damage. + +For ftdisk support, limited success was reported with volume sets on top of +the md driver, although mirror and stripe sets should work as well - if the +md driver can be talked into using the same layout as Windows NT. However, +using the md driver will fail if any of your NTFS partitions have an odd +number of sectors. Please note that the experimental write support is limited to -Windows NT4 and earlier versions. +Windows NT4 and earlier versions at the moment. The ntfs driver supports the following mount options: iocharset=name Character set to use when returning file names. diff -u --recursive --new-file v2.4.1/linux/Documentation/i2c/smbus-protocol linux/Documentation/i2c/smbus-protocol --- v2.4.1/linux/Documentation/i2c/smbus-protocol Thu Dec 16 13:59:38 1999 +++ linux/Documentation/i2c/smbus-protocol Fri Feb 16 15:53:08 2001 @@ -31,7 +31,7 @@ SMBus Write Quick ================= -This sends a single byte to the device, at the place of the Rd/Wr bit. +This sends a single bit to the device, at the place of the Rd/Wr bit. There is no equivalent Read Quick command. A Addr Rd/Wr [A] P diff -u --recursive --new-file v2.4.1/linux/Documentation/ia64/efirtc.txt linux/Documentation/ia64/efirtc.txt --- v2.4.1/linux/Documentation/ia64/efirtc.txt Fri Jul 28 12:50:51 2000 +++ linux/Documentation/ia64/efirtc.txt Thu Feb 8 16:32:44 2001 @@ -13,7 +13,7 @@ EFI provides 4 calls one can make once the OS is booted: GetTime(), SetTime(), GetWakeupTime(), SetWakeupTime() which are all supported by this driver. -We describes those calls as well the the design of the driver in the following +We describe those calls as well the design of the driver in the following sections. II/ Design Decisions diff -u --recursive --new-file v2.4.1/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt --- v2.4.1/linux/Documentation/ioctl-number.txt Mon Dec 11 13:42:08 2000 +++ linux/Documentation/ioctl-number.txt Tue Feb 13 14:13:42 2001 @@ -82,6 +82,7 @@ 'B' C0-FF advanced bbus 'C' all linux/soundcard.h +'D' all asm-s390/dasd.h 'F' all linux/fb.h 'I' all linux/isdn.h 'J' 00-1F drivers/scsi/gdth_ioctl.h diff -u --recursive --new-file v2.4.1/linux/Documentation/isdn/INTERFACE linux/Documentation/isdn/INTERFACE --- v2.4.1/linux/Documentation/isdn/INTERFACE Wed Aug 25 15:18:07 1999 +++ linux/Documentation/isdn/INTERFACE Tue Feb 13 14:13:42 2001 @@ -480,7 +480,7 @@ Parameter: driver = driver-Id command = ISDN_CMD_PROT_IO - arg = The lower 8 Bits define the adressed protocol as defined + arg = The lower 8 Bits define the addressed protocol as defined in ISDN_PTYPE..., the upper bits are used to differenciate the protocol specific CMD. @@ -734,7 +734,7 @@ Parameter: driver = driver-Id command = ISDN_STAT_PROT - arg = The lower 8 Bits define the adressed protocol as defined + arg = The lower 8 Bits define the addressed protocol as defined in ISDN_PTYPE..., the upper bits are used to differenciate the protocol specific STAT. @@ -748,7 +748,7 @@ loading the driver. The LL has to ignore a disabled channel when searching for free channels. The HL driver itself never delivers STAT callbacks for disabled channels. - The LL returns a nonzero code if the operation was not successfull or the + The LL returns a nonzero code if the operation was not successful or the selected channel is actually regarded as busy. Parameter: diff -u --recursive --new-file v2.4.1/linux/Documentation/isdn/README.HiSax linux/Documentation/isdn/README.HiSax --- v2.4.1/linux/Documentation/isdn/README.HiSax Tue Nov 28 21:43:13 2000 +++ linux/Documentation/isdn/README.HiSax Thu Feb 8 10:40:25 2001 @@ -442,6 +442,7 @@ Enrik Berkhan (enrik@starfleet.inka.de) for S0BOX specific stuff Ton van Rosmalen for Teles PCI Petr Novak for Winbond W6692 support + Werner Cornelius for HFC-PCI, HFC-S(+/P) and supplementary services support and more people who are hunting bugs. (If I forgot somebody, please send me a mail). diff -u --recursive --new-file v2.4.1/linux/Documentation/isdn/README.diversion linux/Documentation/isdn/README.diversion --- v2.4.1/linux/Documentation/isdn/README.diversion Fri Jul 28 12:50:51 2000 +++ linux/Documentation/isdn/README.diversion Thu Feb 8 16:32:44 2001 @@ -6,7 +6,7 @@ the HiSax driver. The diversion kernel interface and controlling tool divertctrl were written by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) under the -GNU Public License. +GNU General Public License. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff -u --recursive --new-file v2.4.1/linux/Documentation/isdn/README.hfc-pci linux/Documentation/isdn/README.hfc-pci --- v2.4.1/linux/Documentation/isdn/README.hfc-pci Sun Nov 7 16:34:00 1999 +++ linux/Documentation/isdn/README.hfc-pci Thu Feb 8 10:40:25 2001 @@ -35,7 +35,7 @@ supplied else the parameter is assumed 0 and a auto search for a free card is invoked which may not give the wanted result. -Comments and reports to werner@isdn4linux.de or werner@titro.de . +Comments and reports to werner@isdn4linux.de or werner@isdn-development.de diff -u --recursive --new-file v2.4.1/linux/Documentation/isdn/README.hysdn linux/Documentation/isdn/README.hysdn --- v2.4.1/linux/Documentation/isdn/README.hysdn Mon Aug 21 07:49:02 2000 +++ linux/Documentation/isdn/README.hysdn Thu Feb 8 16:32:44 2001 @@ -2,7 +2,7 @@ The hysdn driver has been written by by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver -under the GNU Public License. +under the GNU General Public License. The CAPI 2.0-support was added by Ulrich Albrecht (ualbrecht@hypercope.de) for Hypercope GmbH Aachen, Germany. diff -u --recursive --new-file v2.4.1/linux/Documentation/kbuild/makefiles.txt linux/Documentation/kbuild/makefiles.txt --- v2.4.1/linux/Documentation/kbuild/makefiles.txt Mon Dec 11 13:19:35 2000 +++ linux/Documentation/kbuild/makefiles.txt Tue Feb 13 14:13:42 2001 @@ -1206,7 +1206,7 @@ mod-subdirs - $(mod-subdirs) is a list of all the the subdirectories that should + $(mod-subdirs) is a list of all the subdirectories that should be added to $(subdir-m), too if they appear in $(subdir-y) Example: diff -u --recursive --new-file v2.4.1/linux/Documentation/magic-number.txt linux/Documentation/magic-number.txt --- v2.4.1/linux/Documentation/magic-number.txt Sun Feb 20 20:37:09 2000 +++ linux/Documentation/magic-number.txt Tue Feb 13 14:13:42 2001 @@ -65,7 +65,6 @@ TTY_MAGIC 0x5401 tty_struct include/linux/tty.h TTY_DRIVER_MAGIC 0x5402 tty_driver include/linux/tty_driver.h TTY_LDISC_MAGIC 0x5403 tty_ldisc include/linux/tty_ldisc.h -SCC_MAGIC 0x8530 scc_channel include/linux/scc.h SPECIALIX_MAGIC 0x0907 specialix_port drivers/char/specialix_io8.h CG_MAGIC 0x090255 ufs_cylinder_group include/linux/ufs_fs.h RPORT_MAGIC 0x525001 r_port drivers/char/rocket_int.h diff -u --recursive --new-file v2.4.1/linux/Documentation/mca.txt linux/Documentation/mca.txt --- v2.4.1/linux/Documentation/mca.txt Wed Aug 18 11:37:51 1999 +++ linux/Documentation/mca.txt Tue Feb 13 14:13:42 2001 @@ -25,7 +25,7 @@ if( MCA_bus ) { slot = mca_find_adapter( ADAPTER_ID, 0 ); if( slot == MCA_NOTFOUND ) { - return ENODEV; + return -ENODEV; } /* optional - see below */ mca_set_adapter_name( slot, "adapter name & description" ); @@ -37,7 +37,7 @@ pos4 = mca_read_stored_pos( slot, 4 ); pos5 = mca_read_stored_pos( slot, 5 ); } else { - return ENODEV; + return -ENODEV; } /* extract configuration from pos[2345] and set everything up */ diff -u --recursive --new-file v2.4.1/linux/Documentation/modules.txt linux/Documentation/modules.txt --- v2.4.1/linux/Documentation/modules.txt Fri Dec 29 14:35:47 2000 +++ linux/Documentation/modules.txt Fri Feb 16 15:53:08 2001 @@ -137,6 +137,39 @@ since umsdos runs piggyback on msdos. +Using modinfo: +-------------- + +Sometimes you need to know what parameters are accepted by a +module or you've found a bug and want to contact the maintainer. +Then modinfo comes in very handy. + +Every module (normally) contains the author/maintainer, +a description and a list of parameters. + +For example "modinfo -a eepro100" will return: + + Maintainer: Andrey V. Savochkin + +and "modinfo -d eepro100" will return a description: + + Intel i82557/i82558 PCI EtherExpressPro driver + +and more important "modinfo -p eepro100" will return this list: + + debug int + options int array (min = 1, max = 8) + full_duplex int array (min = 1, max = 8) + congenb int + txfifo int + rxfifo int + txdmacount int + rxdmacount int + rx_copybreak int + max_interrupt_work int + multicast_filter_limit int + + The "ultimate" utility: ----------------------- diff -u --recursive --new-file v2.4.1/linux/Documentation/networking/00-INDEX linux/Documentation/networking/00-INDEX --- v2.4.1/linux/Documentation/networking/00-INDEX Sat Nov 27 15:27:48 1999 +++ linux/Documentation/networking/00-INDEX Thu Feb 8 16:32:44 2001 @@ -4,32 +4,46 @@ - information on the 3Com EtherLink Plus (3c505) driver. 6pack.txt - info on the 6pack protocol, an alternative to KISS for AX.25 +8139too.txt + - info on the 8139too driver for RTL-8139 based network cards. Configurable - info on some of the configurable network parameters DLINK.txt - info on the D-Link DE-600/DE-620 parallel port pocket adapters PLIP.txt - PLIP: The Parallel Line Internet Protocol device driver +README.sb1000 + - info on General Instrument/NextLevel SURFboard1000 cable modem. alias.txt - info on using alias network devices arcnet-hardware.txt - tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc. arcnet.txt - info on the using the ARCnet driver itself. +atm.txt + - info on where to get ATM programs and support for Linux. ax25.txt - info on using AX.25 and NET/ROM code for Linux baycom.txt - info on the driver for Baycom style amateur radio modems +bridge.txt + - where to get user space programs for ethernet bridging with Linux. +comx.txt + - info on drivers for COMX line of synchronous serial adapters. cops.txt - info on the COPS LocalTalk Linux driver cs89x0.txt - the Crystal LAN (CS8900/20-based) Ethernet ISA adapter driver de4x5.txt - the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver +decnet.txt + - info on using the DECnet networking layer in Linux. depca.txt - the Digital DEPCA/EtherWORKS DE1?? and DE2?? LANCE Ethernet driver dgrs.txt - the Digi International RightSwitch SE-X Ethernet driver +dmfe.txt + - info on the Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver. eql.txt - serial IP load balancing ethertap.txt @@ -38,6 +52,8 @@ - the Digital EtherWORKS 3 DE203/4/5 Ethernet driver filter.txt - Linux Socket Filtering +fore200e.txt + - FORE Systems PCA-200E/SBA-200E ATM NIC driver info. framerelay.txt - info on using Frame Relay/Data Link Connection Identifier (DLCI). ip-sysctl.txt @@ -46,6 +62,10 @@ - IP dynamic address hack e.g. for auto-dialup links ipddp.txt - AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation +iphase.txt + - Interphase PCI ATM (i)Chip IA Linux driver info. +irda.txt + - where to get IrDA (infrared) utilities and info for Linux. lapb-module.txt - programming information of the LAPB module. ltpc.txt @@ -56,22 +76,42 @@ - notes on how NCSA telnet (DOS) breaks with MTU discovery enabled. net-modules.txt - info and "insmod" parameters for all network driver modules. +netdevices.txt + - info on network device driver functions exported to the kernel. +olympic.txt + - IBM PCI Pit/Pit-Phy/Olympic Token Ring driver info. policy-routing.txt - IP policy-based routing pt.txt - the Gracilis Packetwin AX.25 device driver +ray_cs.txt + - Raylink Wireless LAN card driver info. routing.txt - the new routing mechanism shaper.txt - info on the module that can shape/limit transmitted traffic. +sis900.txt + - SiS 900/7016 Fast Ethernet device driver info. +sk98lin.txt + - SysKonnect SK-NET (SK-98xx) Gigabit Ethernet driver info. +skfp.txt + - SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info. smc9.txt - the driver for SMC's 9000 series of Ethernet cards +smctr.txt + - SMC TokenCard TokenRing Linux driver info. soundmodem.txt - Linux driver for sound cards as AX.25 modems tcp.txt - short blurb on how TCP output takes place. +tlan.txt + - ThunderLAN (Compaq Netelligent 10/100, Olicom OC-2xxx) driver info. +tms380tr.txt + - SysKonnect Token Ring ISA/PCI adapter driver info. tulip.txt - info on using DEC 21040/21041/21140 based PCI Ethernet cards. +tuntap.txt + - TUN/TAP device driver, allowing user space Rx/Tx of packets. vortex.txt - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards. wan-router.txt diff -u --recursive --new-file v2.4.1/linux/Documentation/networking/decnet.txt linux/Documentation/networking/decnet.txt --- v2.4.1/linux/Documentation/networking/decnet.txt Fri Jul 28 12:50:51 2000 +++ linux/Documentation/networking/decnet.txt Fri Feb 16 15:53:08 2001 @@ -145,7 +145,7 @@ - What is in the /proc/decnet* files and /proc/sys/net/decnet/* files ? - Which services are you running ? - Which client caused the problem ? - - How much data was being transfered ? + - How much data was being transferred ? - Was the network congested ? - If there was a kernel panic, please run the output through ksymoops before sending it to me, otherwise its _useless_. diff -u --recursive --new-file v2.4.1/linux/Documentation/networking/smc9.txt linux/Documentation/networking/smc9.txt --- v2.4.1/linux/Documentation/networking/smc9.txt Sat Nov 29 10:33:18 1997 +++ linux/Documentation/networking/smc9.txt Thu Feb 8 16:32:44 2001 @@ -3,7 +3,7 @@ Revision 0.12 3/5/96 Copyright 1996 Erik Stahlman -Released under terms of the GNU public license. +Released under terms of the GNU General Public License. This file contains the instructions and caveats for my SMC9xxx driver. You should not be using the driver without reading this file. diff -u --recursive --new-file v2.4.1/linux/Documentation/s390/TAPE linux/Documentation/s390/TAPE --- v2.4.1/linux/Documentation/s390/TAPE Wed Dec 31 16:00:00 1969 +++ linux/Documentation/s390/TAPE Fri Feb 16 15:53:08 2001 @@ -0,0 +1,125 @@ +Channel attached Tape device driver + +-----------------------------WARNING----------------------------------------- +This driver is considered to be EXPERIMENTAL. Do NOT use it in +production environments. Feel free to test it and report problems back to us. +----------------------------------------------------------------------------- + +The LINUX for zSeries tape device driver manages channel attached tape drives +which are compatible to IBM 3480 or IBM 3490 magnetic tape subsystems. This +includes various models of these devices (for example the 3490E). + + +Tape driver features + +The device driver supports a maximum of 128 tape devices. +No official LINUX device major number is assigned to the zSeries tape device +driver. It allocates major numbers dynamically and reports them on system +startup. +Typically it will get major number 254 for both the character device front-end +and the block device front-end. + +The tape device driver needs no kernel parameters. All supported devices +present are detected on driver initialization at system startup or module load. +The devices detected are ordered by their subchannel numbers. The device with +the lowest subchannel number becomes device 0, the next one will be device 1 +and so on. + + +Tape character device front-end + +The usual way to read or write to the tape device is through the character +device front-end. The zSeries tape device driver provides two character devices +for each physical device -- the first of these will rewind automatically when +it is closed, the second will not rewind automatically. + +The character device nodes are named /dev/rtibm0 (rewinding) and /dev/ntibm0 +(non-rewinding) for the first device, /dev/rtibm1 and /dev/ntibm1 for the +second, and so on. + +The character device front-end can be used as any other LINUX tape device. You +can write to it and read from it using LINUX facilities such as GNU tar. The +tool mt can be used to perform control operations, such as rewinding the tape +or skipping a file. + +Most LINUX tape software should work with either tape character device. + + +Tape block device front-end + +The tape device may also be accessed as a block device in read-only mode. +This could be used for software installation in the same way as it is used with +other operation systems on the zSeries platform (and most LINUX +distributions are shipped on compact disk using ISO9660 filesystems). + +One block device node is provided for each physical device. These are named +/dev/btibm0 for the first device, /dev/btibm1 for the second and so on. +You should only use the ISO9660 filesystem on LINUX for zSeries tapes because +the physical tape devices cannot perform fast seeks and the ISO9660 system is +optimized for this situation. + + +Tape block device example + +In this example a tape with an ISO9660 filesystem is created using the first +tape device. ISO9660 filesystem support must be built into your system kernel +for this. +The mt command is used to issue tape commands and the mkisofs command to +create an ISO9660 filesystem: + +- create a LINUX directory (somedir) with the contents of the filesystem + mkdir somedir + cp contents somedir + +- insert a tape + +- ensure the tape is at the beginning + mt -f /dev/ntibm0 rewind + +- set the blocksize of the character driver. The blocksizes 512, 1024 + and 2048 bytes are supported by ISO9660. 1024 is the default, u + which will be used here. + mt -f /dev/ntibm0 setblk 1024 + +- write the filesystem to the character device driver + mkisofs -o /dev/ntibm0 somedir + +- rewind the tape again + mt -f /dev/ntibm0 rewind + +- Now you can mount your new filesystem as a block device: + mount -t iso9660 -o ro,block=1024 /dev/btibm0 /mnt + +TODO List + +- The backend code has to be enhanced to support error-recovery actions. + +- The seeking algorithm of the block device has to be improved to speed + things up + +BUGS + +There are lots of weaknesses still in the code. This is why it is EXPERIMENTAL. +If an error occurs which cannot be handled by the code you will get a +sense-data dump.In that case please do the following: + +1. set the tape driver debug level to maximum: + echo 6 >/proc/s390dbf/tape/level + +2. re-perform the actions which produced the bug. (Hopefully the bug will + reappear.) + +3. get a snapshot from the debug-feature: + cat /proc/s390dbf/tape/hex_ascii >somefile + +4. Now put the snapshot together with a detailed description of the situation + that led to the bug: + - Which tool did you use? + - Which hardware do you have? + - Was your tape unit online? + - Is it a shared tape unit? + +5. Send an email with your bug report to: + mailto:Linux390@de.ibm.com + + diff -u --recursive --new-file v2.4.1/linux/Documentation/s390/cds.txt linux/Documentation/s390/cds.txt --- v2.4.1/linux/Documentation/s390/cds.txt Thu Oct 12 14:19:31 2000 +++ linux/Documentation/s390/cds.txt Fri Feb 16 15:53:08 2001 @@ -539,7 +539,7 @@ Possible flag values are : -DOIO_EARLY_NOTIFICATION - allow for early interupt notification +DOIO_EARLY_NOTIFICATION - allow for early interrupt notification DOIO_VALID_LPM - LPM input parameter is valid (see usage notes below for details) DOIO_WAIT_FOR_INTERRUPT - wait synchronously for final status @@ -549,7 +549,7 @@ typedef struct { char cmd_code; /* command code */ - char flags; /* flags, like IDA adressing, etc. */ + char flags; /* flags, like IDA addressing, etc. */ unsigned short count; /* byte count */ void *cda; /* data address */ } ccw1_t __attribute__ ((aligned(8))); diff -u --recursive --new-file v2.4.1/linux/Documentation/s390/chandev.8 linux/Documentation/s390/chandev.8 --- v2.4.1/linux/Documentation/s390/chandev.8 Wed Dec 31 16:00:00 1969 +++ linux/Documentation/s390/chandev.8 Fri Feb 16 15:53:08 2001 @@ -0,0 +1,306 @@ +.TH chandev 8 +.SH NAME +channel device layer +.Dd December 6, 2000 +.Os Linux for Zseries + +.SH SYNOPSIS +The channel device layer is a layer to provide a consistent interface for +configuration & default machine check (devices appearing & disappearing ) +handling Linux for zSeries channel devices. + +These include among others + +.Bl -item +.It +lcs ( the most common ethernet/token ring/fddi standard on zSeries ) +.It +ctc/escon hi speed like serial link standard on zSeries. +.It +claw used to talk to cisco routers. +.It +qeth gigabit ethernet. +.El + +These devices use two channels one read & one write for configuration & +or communication. +The motivation behind producing this layer was that there is a lot of +duplicate code among the drivers for configuration so the lcs & ctc drivers +tended to fight over 3088/08's & 3088/1F's which could be either 2216/3172 +lcs compatible devices or escons/ctc's & to resolve this fight +both device drivers had to be reconfigured rather than doing the +configuration in a single place. + +.SH DESCRIPTION +The current setup can be read from /proc/chandev +arguments can be entered by... +.Bl -enum +.It +Piping to /proc/chandev. +.It +Entering them into /etc/chandev.conf comments are prefixed #. +.It +Or from the boot command line using the 'chandev=' keyword +.El +Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. The script /bin/chandev will be called automatically on startup or a machine check of a device as follows. +/bin/chandev . + +e.g. if tr0 & ctc0 were starting up & eth0 & eth1 didn't recover from a gone machine check at the same instant the parameters would be. + + +/bin/chandev start tr0 ctc0 machine_check eth0 gone gone eth1 gone gone + + +This can be used for example to call /etc/rc.d/init.d/network start when a device appears & make the ipldelay kernel boot parameter obselete on native machines or recover from bad machine checks where the default machine check handling isn't adequete. The machine checks that can be presented as parameters are good not_operational no_path revalidate device_gone. + +valid chandev arguments are <> indicate optional parameters, | indicate a choice. + +.B glossary +.Bl -item +.It +devno: is a 16 bit unsigned number used to uniquely identify a subchannel to a device. +.It +force list: is a term specific to channel device layer describing a range of devno's to be forced to configure in a particular manner as opposed to autodetect +.El + +.B commonly used options + +.Bl -item +.It + +.Bl -item + +.It +.B (ctc|escon|lcs|osad|qeth|claw), +read_devno, write_devno, , , +.It +e.g. ctc0,0x7c00,0x7c01,0,0,0 +.It +Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( normally 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter. +.El +.It + +.Bl -item +.It +.B add_parms +,chan_type, +.It +chan_type bitfield +.It +ctc=0x1, escon=0x2, lcs=0x4, osad=0x8, qeth=0x10, claw=0x20. +.It +This is for device driver specific options passed as a string to the driver +not dealt with by the channel device layer it can't contain spaces. +.El +.It + +.Bl -item +.It +.B del_parms +<,chan_type,exact_match> +.It +This deletes some or all device driver specific options not specifying chan_type causes it to delete all the strings. exact_match=1 specifies only to remove driver parms where chan_type is exactly equal exact_match=0 specifies to remove parms where any bit matches chan_type. +.El +.It + +.Bl -item +.It +.B noauto +,- +.It +Don't probe a range of device numbers for channel devices. +.El +.It + +.Bl -item +.It +.B use_devno_names +.It +Tells the channel layer to assign device names based on the read channel cuu number. +.It +e.g. a token ring read channel 0x7c00 would have an interface called tr0x7c00 this avoids name collisions on devices. +.El +.El + + +.B power user options + + +.Bl -item + +.It +.Bl -item +.It +.B del_noauto +, +.It + Delete a range or all noauto ranges when devno is within a range. +.El + +.It +.Bl -item +.It +.B del_force +,read_devno +.It +Delete a forced channel device from force list. +.El + +.It +.Bl -item +.It +.B dont_use_devno_names +.It +Opposite to use_devno_names described above. +.El + + +.It +.Bl -item +.It +.B add_model +,chan_type, cu_type, cu_model, dev_type, dev_model, max_port_no, automatic_machine_check_handling + +.It +Tells the channel layer to probe for the device described, -1 for any of the parameters other than chan_type & automatic_machine_check_handling is a wildcard. +Set max_port_no to 0 for non lcs devices. +.It +auto machine check recovery bitfield +.It +not_operational=0x1, no_path=0x2, revalidate=0x4, gone=0x8 +.It +chan_type bitfield +.It +ctc=0x1, escon=0x2, lcs=0x4, osad=0x8, qeth=0x10, claw=0x20 + +.It +.Bl -item +.It +.B del_model +,cu_type,cu_model,dev_type,dev_model +.It +-1 for any parameter is a wildcard, +.El +.It +.B del_all_models +.It +.Bl -item +.It +.B auto_msck +<,lo_devno>,,auto_msck_recovery +.It +This is used to specify the kind of machine check recovery that occurs over a device range. +.El +.It +.Bl -item +.It +.B del_auto_msck +<,devno> +.It +Delete a range or all machine check recovery ranges when devno is within a range. +.El +.It +.Bl -item +.It +.B reset_clean +.It +Resets all model info, forced devices & noauto lists to null. +.El +.It +.Bl -item +.It +.B reset_conf +.It +Resets all model info, forced devices & noauto lists back to default settings. +.El +.It +.Bl -item +.It +.B reset_conf_clean +.It +Resets all model info, forced devices & noauto lists to empty. +.El +.It +.Bl -item +.It +.B shutdown + +.It +Shuts down a particular device by device name or read devno, +deregisters it & releases its interrupts +or shuts down all devices if no parameter is used. +.El +.It +.Bl -item +.It +.B reprobe +.It +Calls probe method for channels whose interrupts are not owned. +.El +.It +.Bl -item +.It +.B read_conf +.It +Read instructions from /etc/chandev.conf. +.El +.It +.Bl -item +.It +.B dont_read_conf +.It +Don't automatically read /etc/chandev.conf on boot. +.El +.It +e.g the following sequence of commands should be roughly equivalent +to rebooting for channel devices. +.Bl -item +.It +shutdown +.It +reset_conf +.It +read_conf +.It +reprobe +.El +.El + +.SH SEE ALSO +.Bl -item +.It +If you wish to write a driver channel device layer compatible +.It +/linux/include/asm-s390/chandev.h for the apis which are commented. +.It +/linux/drivers/s390/misc/chandev.c for the code. +.El + +.SH FILES +.Bl -item +.It +.B /proc/chandev +.It +cat /proc/chandev to see current options chosen. +.Iy +echo >proc/chandev to enter a new command +.It +.B /etc/chandev.conf +.It +A file which can be used to configure the channel +device layer. +.It +kernel parameters with the +.B 'chandev=' +keyword. +.It +.B /bin/chandev +.It +A user script/executable which is run when devices come online "appear" +or go offline "disappear". +.El + + +.SH AUTHORS +DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + diff -u --recursive --new-file v2.4.1/linux/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt --- v2.4.1/linux/Documentation/scsi-generic.txt Mon Aug 21 08:57:35 2000 +++ linux/Documentation/scsi-generic.txt Thu Feb 8 16:32:44 2001 @@ -314,7 +314,7 @@ (limit is SG_MAX_QUEUE (16) outstanding packets per file descriptor). However, for backward compatibility, command queuing is turned off by default (#define SG_DEF_COMMAND_Q 0 in sg.h). This can be changed -via the the SG_SET_COMMAND_Q ioctl() [or by recompiling after changing +via the SG_SET_COMMAND_Q ioctl() [or by recompiling after changing the above define to 1]. In this sg driver a write() should return more or less immediately. diff -u --recursive --new-file v2.4.1/linux/Documentation/sound/AWE32 linux/Documentation/sound/AWE32 --- v2.4.1/linux/Documentation/sound/AWE32 Tue Apr 11 19:13:15 2000 +++ linux/Documentation/sound/AWE32 Fri Feb 16 15:53:08 2001 @@ -3,103 +3,74 @@ This documentation is devoted to the Creative Sound Blaster AWE32, AWE64 and SB32. -1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This is -important, because the driver works only with real Creative cards. +1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This + is important, because the driver works only with real Creative cards. -2) If your card is NOT "Plug-n-Play" then go to 5th step now. In the other case -proceed to step 3. +2) The first thing you need to do is re-compile your kernel with support for + your sound card. Run your favourite tool to configure the kernel and when + you get to the "Sound" menu you should enable support for the following: -3) You should compile in kernel ISAPnP support or you should obtain isapnptools. -If you choose kernel level ISAPnP skip to step 5. I looked through other PnP -packages for Linux, but all they are either in deep unstable beta/alpha releases -or they are much worse than isapnptools. In my case isapnptools were included in -a Linux distribution (Red Hat 5.x). If you also already have them then go to -step 4. + Sound card support, + OSS sound modules, + 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support, + AWE32 synth -The latest copy of isapnptools-1.17 is available from -ftp://sunsite.unc.edu/pub/Linux/system/hardware/isapnptools-1.17.tgz -You should gunzip/untar it to something like /usr/local/ -(cp isapnptools-1.17.tgz /usr/local/; cd /usr/local/; -tar -xzf isapnptools-1.17.tgz). + If your card is "Plug and Play" you will also need to enable these two + options, found under the "Plug and Play configuration" menu: -Compile the package (make) and install it (make install). -If something goes wrong check the INSTALL file in isapnptools-1.15 directory. + Plug and Play support + ISA Plug and Play support -4) Now do a "pnpdump > /etc/isapnp.conf". File /etc/isapnp.conf will contain -info about PnP devices you may have. If you want you can read the manual page -about isapnp.conf file (man isapnp.conf). Most lines of your isapnp.conf file are -commented. You should uncomment lines which don't conflict with your -configuration. + Now compile and install the kernel in normal fashion. If you don't know + how to do this you can find instructions for this in the README file + located in the root directory of the kernel source. -ATTENTION! Device Audio should have 1 IRQ, 2 DMA and 3 base I/O resources. -If you don't have such a configuration you should manually add the resources to -the isapnp.conf file. After editing I got these lines in the Audio device -section (I ripped out all the comments): +3) Before you can start playing midi files you will have to load a sound + bank file. The utility needed for doing this is called "sfxload", and it + is one of the utilities found in a package called "awesfx". If this + package is not available in your distribution you can download the AWE + snapshot from Creative Labs Open Source website: -"(CONFIGURE CTL0044/1132685 (LD 0 (INT 0 (IRQ 5 (MODE +E))) (DMA 0 (CHANNEL 1)) - (DMA 1 (CHANNEL 5)) (IO 0 (BASE 0x220)) (IO 1 (BASE 0x330)) (IO 2 (BASE 0x388)) - (ACT Y)))" + http://www.opensource.creative.com/snapshot.html -(In your case CTL044/1132685 numbers may be other) + Once you have unpacked the AWE snapshot you will see a "awesfx" + directory. Follow the instructions in awesfx/docs/INSTALL to install the + utilities in this package. After doing this, sfxload should be installed + as: -Don't forget to uncomment (ACT Y)! + /usr/local/bin/sfxload -The next device is the on-board IDE controller. You may enable it if you wish, -but it will not effect sound. + To enable AWE general midi synthesis you should also get the sound bank + file for general midi from: -Then WaveTable goes. For some reason Plug-n-Play detects only one I/O port, -but the wavetable needs THREE! My working string is: + http://members.xoom.com/yar/synthgm.sbk.gz -"(CONFIGURE CTL044/1132685 (LD 2 (IO 0 (BASE 0x0620)) (IO 1 (BASE 0x0A20)) -(IO 2 (BASE 0x0E20)) (ACT Y) ))" + Copy it to a directory of your choice, and unpack it there. -Resources 0x0620, 0x0A20 and 0x0E20 should work. Other on-board devices: -Gameport and StereoEnhance are not required to be initialized. +4) Edit /etc/modules.conf, and insert the following lines at the end of the + file: -Now you can execute "isapnp /etc/isapnp.conf". No errors should be reported. -If you correctly installed isapnptools, then isapnp will run every boot time. + alias sound-slot-0 sb + alias sound-service-0-1 awe_wave + post-install awe_wave /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE -5) Now you should recompile the kernel. + You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full + path of of the sound bank file. That will enable the Sound Blaster and AWE + wave synthesis. To play midi files you should get one of these programs if + you don't already have them: -In "make (x,menu)config" select in "Sound": -"Sound card support", "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support", -"Generic OPL2/OPL3 FM synthesizer support" and "FM synthesizer (YM3812/OPL-3) -support" as (module). + Playmidi: http://playmidi.openprojects.net -In "make (x,menu)config" select in "Sound": -select "OSS sound modules" as (module) -select "AWE32 Synth" as (module) + AWEMidi Player (drvmidi) Included in the previously mentioned AWE + snapshot. -Now recompile the kernel (make dep; make (b)zImage, b(z)lilo, etc...; -make modules; make modules_install), update your boot loader (if required) and -boot new kernel. + You will probably have to pass the "-e" switch to playmidi to have it use + your midi device. drvmidi should work without switches. -6) If awesfx program is not included in your distribution, then download it -from http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/index.html#Latest. -Compile it. Copy sfxload program to /usr/bin. To enable AWE general midi -synthesis you should also get the sound bank file for general midi from -http://members.xoom.com/yar/synthgm.sbk.gz. Copy it to /usr and gunzip it there. + If something goes wrong please e-mail me. All comments and suggestions are + welcome. -7) Edit /etc/modules.conf, inserting at the end of the file: + Yaroslav Rosomakho (alons55@dialup.ptt.ru) + http://www.yar.opennet.ru -alias midi awe_wave -post-install awe_wave /usr/bin/sfxload /usr/synthfm.sbk - -That will enable the Sound Blaster and AWE wave synthesis. - -To play midi files you should get one of these programs: - -Playmidi 2.4 or higher: http://playmidi.openprojects.net -Drvmidi: http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/index.html#Latest - -(These are available at all major Linux FTP sites and may already be - in your distribution) -Remember to use -a switch if you have playmidi as a compiled binary (ex. RPM) - -If something goes wrong please e-mail me. All comments and suggestions are -welcome. - - Yaroslav Rosomakho (alons55@dialup.ptt.ru) - http://www.yar.opennet.ru - -Last Updated: 10Apr2000 +Last Updated: Feb 3 2001 diff -u --recursive --new-file v2.4.1/linux/Documentation/sound/Introduction linux/Documentation/sound/Introduction --- v2.4.1/linux/Documentation/sound/Introduction Wed Sep 27 13:53:52 2000 +++ linux/Documentation/sound/Introduction Fri Feb 16 15:53:08 2001 @@ -1,15 +1,19 @@ Introduction Notes on Modular Sound Drivers and Soundcore Wade Hampton -6/30/1999 +2/14/2001 Purpose: ======== This document provides some general notes on the modular sound drivers and their configuration, along with the -support modules sound.o, soundlow.o and soundcore.o. +support modules sound.o and soundcore.o. Note, some of this probably should be added to the Sound-HOWTO! +Note, soundlow.o was present with 2.2 kernels but is not +required for 2.4.x kernels. References have been removed +to this. + Copying: ======== @@ -28,6 +32,8 @@ 1.1.1 19991031 Added notes on sound-slot- and sound-service. (Alan Cox) 1.1.2 20000920 Modified for Kernel 2.4 (Christoph Hellwig) +1.1.3 20010214 Minor notes and corrections (Wade Hampton) + Added examples of sound-slot-0, etc. Modular Sound Drivers: @@ -69,8 +75,9 @@ 1. There is a new OpenSource sound driver called ALSA which is currently under development: http://www.alsa-project.org/ - I have not tried it nor am I aware of its status, but it is - currently under development. + The ALSA drivers support some newer hardware that may not + be supported by this sound driver and also provide some + additional features. 2. The commercial OSS driver may be obtained from the site: http://www/opensound.com. This may be used for cards that @@ -82,7 +89,8 @@ some of the requirements for multiple sound card systems. For more information, see: http://www.tux.org/~ricdude/EsounD.html The "esd" program may be used with the real-player and mpeg - players like mpg123 and x11amp. + players like mpg123 and x11amp. The newer real-player + and some games even include built-in support for ESD! Building the Modules: @@ -104,13 +112,31 @@ 4. Select your sound driver(s) as a module. For ProAudio, Sound Blaster, etc., select M (module) for OSS sound modules. - [thanks to marvin stodolsky ]A + [thanks to Marvin Stodolsky ]A 5. Make the kernel (e.g., make dep ; make bzImage), and install the kernel. 6. Make the modules and install them (make modules; make modules_install). +Note, for 2.4.x kernels, make sure you have the newer modutils +loaded or modules will not be loaded properly. 2.4.x changed the +layout of /lib/modules/2.4.x and requires an updated modutils. + + +Plug and Play (PnP: +=================== + +If the sound card is an ISA PnP card, isapnp may be used +to configure the card. See the file isapnp.txt in the +directory one level up (e.g., /usr/src/linux/Documentation). + +Also the 2.4.x kernels provide PnP capabilities, see the +file NEWS in this directory. + +PCI sound cards are highly recommended, as they are far +easier to configure and from what I have read, they use +less resources and are more CPU efficient. INSMOD: @@ -129,7 +155,6 @@ # echo Starting sound /sbin/insmod soundcore -/sbin/insmod soundlow /sbin/insmod sound # echo Starting sound blaster.... @@ -160,6 +185,10 @@ The status of sound may be read/checked by: cat (anyfile).au >/dev/audio +[WWH: This may not work properly for SoundBlaster PCI 128 cards +such as the es1370/1 (see the es1370/1 files in this directory) +as they do not automatically support uLaw on /dev/audio.] + The status of the modules and which modules depend on which other modules may be checked by: /sbin/lsmod @@ -168,7 +197,6 @@ sb 26280 0 uart401 5640 0 [sb] sound 57112 0 [sb uart401] - soundlow 208 0 [sound] soundcore 1968 8 [sb sound] @@ -186,7 +214,6 @@ /sbin/rmmod sb /sbin/rmmod uart401 /sbin/rmmod sound -/sbin/rmmod soundlow /sbin/rmmod soundcore When using sound as a module, I typically put these commands @@ -217,7 +244,8 @@ Typically, you need two sound cards of different types. Note, this uses more precious interrupts and DMA channels and sometimes can be a configuration nightmare. I have heard reports of 3-4 -sound cards (typically I only use 2). +sound cards (typically I only use 2). You can sometimes use +multiple PCI sound cards of the same type. On my machine I have two sound cards (cs4232 and Soundblaster Vibra 16). By loading sound as modules, I can control which is the first @@ -236,7 +264,7 @@ 1. Copy the sound modules to a new name. For example sb.o could be copied (or symlinked) to sb1.o for the - second SoundBlasster. + second SoundBlaster. 2. Make a second entry in /etc/modules.conf, for example, sound1 or sb1. This second entry should refer to the @@ -257,6 +285,7 @@ supports multiple cards with one module by default. Read the file 'Soundblaster' in this directory for details. + Sound Problems: =============== @@ -314,7 +343,6 @@ esddsp may be used to play files via a non-esd aware program. - 6) Ask for help on the sound list or send E-MAIL to the sound driver author/maintainer. @@ -327,6 +355,9 @@ This makes the sound system allocate its buffers and hang onto them. + You may also set persistent DMA when building a 2.4.x kernel. + + Configuring Sound: ================== @@ -354,10 +385,11 @@ Anyone want to write a linuxconf module for configuring sound? + Module Loading: =============== -When a sound card is first referenced and sound is modular the sound system +When a sound card is first referenced and sound is modular, the sound system will ask for the sound devices to be loaded. Initially it requests that the driver for the sound system is loaded. It then will ask for sound-slot-0, where 0 is the first sound card. (sound-slot-1 the second and @@ -370,11 +402,32 @@ a midi synth in all cases then it will request "sound-service-0-n" where n is -0 Mixer + 0 Mixer + + 2 MIDI + + 3, 4 DSP audio + -2 MIDI +For example, I use the following to load my Soundblaster PCI 128 +(ES 1371) card first, followed by my SoundBlaster Vibra 16 card, +then by my TV card: -3, 4 DSP audio +# Load the Soundblaster PCI 128 as /dev/dsp, /dev/dsp1, /dev/mixer +alias sound-slot-0 es1371 + +# Load the Soundblaster Vibra 16 as /dev/dsp2, /dev/mixer1 +alias sound-slot-1 sb +options sb io=0x240 irq=5 dma=1 dma16=5 mpu_io=0x330 + +# Load the BTTV (TV card) as /dev/mixer2 +alias sound-slot-2 bttv +alias sound-service-2-0 tvmixer + +pre-install bttv modprobe tuner ; modprobe tvmixer +pre-install tvmixer modprobe msp3400; modprobe tvaudio +options tuner debug=0 type=8 +options bttv card=0 radio=0 pll=0 For More Information (RTFM): @@ -405,3 +458,4 @@ Contact Information: ==================== Wade Hampton: (whampton@staffnet.com) + diff -u --recursive --new-file v2.4.1/linux/Documentation/sound/Maestro3 linux/Documentation/sound/Maestro3 --- v2.4.1/linux/Documentation/sound/Maestro3 Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/Maestro3 Sun Feb 4 10:05:29 2001 @@ -0,0 +1,84 @@ + An OSS/Lite Driver for the ESS Maestro3 family of sound chips + + Zach Brown, January 2001 + +Driver Status and Availability +------------------------------ + +The most recent version of this driver will hopefully always be available at + http://www.zabbo.net/maestro3/ + +I will try and maintain the most recent stable version of the driver +in both the stable and development kernel lines. + +Historically I've sucked pretty hard at actually doing that, however. + +ESS Maestro3 Chip Family +----------------------- + +The 'Maestro3' is much like the Maestro2 chip. The noted improvement +is the removal of the silicon in the '2' that did PCM mixing. All that +work is now done through a custom DSP called the ASSP, the Asynchronus +Specific Signal Processor. + +The 'Allegro' is a baby version of the Maestro3. I'm not entirely clear +on the extent of the differences, but the driver supports them both :) + +The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998, +both under ESS's vendor ID of 0x125D. The Maestro3 can also show up as +0x199a when hardware strapping is used. + +The chip can also act as a multi function device. The modem IDs follow +the audio multimedia device IDs. (so the modem part of an Allegro shows +up as 0x1989) + +Driver OSS Behavior +-------------------- + +This OSS driver exports /dev/mixer and /dev/dsp to applications, which +mostly adhere to the OSS spec. This driver doesn't register itself +with /dev/sndstat, so don't expect information to appear there. + +The /dev/dsp device exported behaves as expected. Playback is +supported in all the various lovely formats. 8/16bit stereo/mono from +8khz to 48khz, with both read()/write(), and mmap(). + +/dev/mixer is an interface to the AC'97 codec on the Maestro3. It is +worth noting that there are a variety of AC'97s that can be wired to +the Maestro3. Which is used is entirely up to the hardware implementor. +This should only be visible to the user by the presence, or lack, of +'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them. +The Allegro has an onchip AC'97. + +The driver doesn't support MIDI or FM playback at the moment. + +Compiling and Installing +------------------------ + +With the drivers inclusion into the kernel, compiling and installing +is the same as most OSS/Lite modular sound drivers. Compilation +of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable +in the config system. + +It may be modular or statically linked. If it is modular it should be +installed with the rest of the modules for the kernel on the system. +Typically this will be in /lib/modules/ somewhere. 'alias sound-slot-0 +maestro3' should also be added to your module configs (typically +/etc/modules.conf) if you're using modular OSS/Lite sound and want to +default to using a maestro3 chip. + +There are very few options to the driver. One is 'debug' which will +tell the driver to print minimal debugging information as it runs. This +can be collected with 'dmesg' or through the klogd daemon. + +The other is 'external_amp', which tells the driver to attempt to enable +an external amplifier. This defaults to '1', you can tell the driver +not to bother enabling such an amplifier by setting it to '0'. + +Power Management +---------------- + +This driver has a minimal understanding of PCI Power Management. It will +try and power down the chip when the system is suspended, and power +it up with it is resumed. It will also try and power down the chip +when the machine is shut down. diff -u --recursive --new-file v2.4.1/linux/Documentation/sound/NM256 linux/Documentation/sound/NM256 --- v2.4.1/linux/Documentation/sound/NM256 Mon Oct 25 08:26:52 1999 +++ linux/Documentation/sound/NM256 Sun Feb 4 10:05:29 2001 @@ -53,7 +53,7 @@ compatible OSS driver with these chipsets. I cannot provide any assistance with machines using the SB16, AD1848 or CS4232 compatible versions. (The driver now attempts to detect the mixer version, and -will refuse to load if it believes the hardware is not not +will refuse to load if it believes the hardware is not AC97-compatible.) The sound support is very basic, but it does include simultaneous diff -u --recursive --new-file v2.4.1/linux/Documentation/sound/OPL3-SA2 linux/Documentation/sound/OPL3-SA2 --- v2.4.1/linux/Documentation/sound/OPL3-SA2 Wed May 24 19:28:05 2000 +++ linux/Documentation/sound/OPL3-SA2 Sun Feb 4 10:05:29 2001 @@ -2,22 +2,26 @@ --------------------------------------------------------------- Scott Murray, scott@spiteful.org -January 5, 1999 +January 7, 2001 NOTE: All trade-marked terms mentioned below are properties of their respective owners. + +Supported Devices +----------------- + This driver is for PnP soundcards based on the following Yamaha audio controller chipsets: YMF711 aka OPL3-SA2 -YMF715 aka OPL3-SA3 -YMF719 aka OPL3-SAx (?) +YMF715 and YMF719 aka OPL3-SA3 -I'm a little fuzzy on what exactly is classified a SAx, as I've seen -the label used to refer to the whole 7xx family and as a specific -identifier for the 719 on my no-name soundcard. To make matters -worse, there seem to be several revisions of the 715 chipset. +Up until recently (December 2000), I'd thought the 719 to be a +different chipset, the OPL3-SAx. After an email exhange with +Yamaha, however, it turns out that the 719 is just a re-badged +715, and the chipsets are identical. The chipset detection code +has been updated to refkect this. Anyways, all of these chipsets implement the following devices: @@ -31,75 +35,142 @@ device and the MSS device. Since the MSS device has better capabilities, I have implemented the driver to use it. -Being PnP cards, some configuration is required. There are two ways -of doing this. The most common is to use the isapnptools package to -initialize the card, and use the kernel module form of the sound -subsystem and sound drivers. Alternatively, some BIOS's allow manual -configuration of installed PnP devices in a BIOS menu, which should -allow using the non-modular sound drivers, i.e. built into the kernel. + +Mixer Channels +-------------- + +Older versions of this driver (pre-December 2000) had two mixers, +an OPL3-SA2 or SA3 mixer and a MSS mixer. The OPL3-SA[23] mixer +device contained a superset of mixer channels consisting of its own +channels and all of the MSS mixer channels. To simplify the driver +considerably, and to partition functionality better, the OPL3-SA[23] +mixer device now contains has its own specific mixer channels. They +are: + +Volume - Hardware master volume control +Bass - SA3 only, now supports left and right channels +Treble - SA3 only, now supports left and right channels +Microphone - Hardware microphone input volume control +Digital1 - Yamaha 3D enhancement "Wide" mixer + +All other mixer channels (e.g. "PCM", "CD", etc.) now have to be +controlled via the "MS Sound System (CS4231)" mixer. To facilitate +this, the mixer device creation order has been switched so that +the MSS mixer is created first. This allows accessing the majority +of the useful mixer channels even via single mixer-aware tools +such as "aumix". + + +Plug 'n Play +------------ + +In previous kernels (2.2.x), some configuration was required to +get the driver to talk to the card. Being the new millenium and +all, the 2.4.x kernels now support auto-configuration if ISA PnP +support is configured in. Theoretically, the driver even supports +having more than one card in this case. + +With the addition of PnP support to the driver, two new parameters +have been added to control it: + +isapnp - set to 0 to disable ISA PnP card detection + +multiple - set to 0 to disable multiple PnP card detection + + +Optional Parameters +------------------- + +Recent (December 2000) additions to the driver (based on a patch +provided by Peter Englmaier) are two new parameters: + +ymode - Set Yamaha 3D enhancement mode: + 0 = Desktop/Normal 5-12 cm speakers + 1 = Notebook PC (1) 3 cm speakers + 2 = Notebook PC (2) 1.5 cm speakers + 3 = Hi-Fi 16-38 cm speakers + +loopback - Set A/D input source. Useful for echo cancellation: + 0 = Mic Right channel (default) + 1 = Mono output loopback + +The ymode parameter has been tested and does work. The loopback +parameter, however, is untested. Any feedback on its usefulness +would be appreciated. + + +Manual Configuration +-------------------- + +If for some reason you decide not to compile ISA PnP support into +your kernel, or disabled the driver's usage of it by setting the +isapnp parameter as discussed above, then you will need to do some +manual configuration. There are two ways of doing this. The most +common is to use the isapnptools package to initialize the card, and +use the kernel module form of the sound subsystem and sound drivers. +Alternatively, some BIOS's allow manual configuration of installed +PnP devices in a BIOS menu, which should allow using the non-modular +sound drivers, i.e. built into the kernel. I personally use isapnp and modules, and do not have access to a PnP -BIOS machine to test. If you have such a beast, try building both the -MSS driver and this driver into the kernel (appropriately configured, -of course). I have received reports of this working, so it should be -possible for most people with PnP BIOS. If it does not work for you, -then email me if you are willing to experiment in an effort to make it -work. - -************************************************************************ -* I have now had two such machines, and I have fixed this to work -* properly when built into the kernel. The Toshiba Libretto series, or -* at least models 70CT and 110CT which I have owned, use a Yamaha -* OPL3-SAx (OPL3-SA3 according to documentation) sound chip, IRQ 5, -* IO addresses 220/530/388/330/370 and DMA 1,0 (_not_ 0,1). All these -* configuration settings can be gathered by booting another OS which -* recognizes the card already. -* -* I have made things 'just work' for the non-modular case on such -* machines when configured properly. -* -* David Luyer -************************************************************************ - -If you are using isapnp, follow the directions in its documentation to -produce a configuration file. Here is the relevant excerpt I use for -my SAx card from my isapnp.conf: +BIOS machine to test. If you have such a beast, configuring the +driver to be built into the kernel should just work (thanks to work +done by David Luyer ). You will still need +to specify settings, which can be done by adding: + +opl3sa2=,,,,, + +to the kernel command line. For example: + +opl3sa2=0x370,5,0,1,0x530,0x330 + +If you are instead using the isapnp tools (as most people have been +before Linux 2.4.x), follow the directions in their documentation to +produce a configuration file. Here is the relevant excerpt I used to +use for my SA3 card from my isapnp.conf: (CONFIGURE YMH0800/-1 (LD 0 -# Instead of (IO 0 (BASE 0x0220)), disable SB: -(IO 0 (BASE 0x0000)) +# NOTE: IO 0 is for the unused SoundBlaster part of the chipset. +(IO 0 (BASE 0x0220)) (IO 1 (BASE 0x0530)) (IO 2 (BASE 0x0388)) (IO 3 (BASE 0x0330)) (IO 4 (BASE 0x0370)) -(INT 0 (IRQ 7 (MODE +E))) +(INT 0 (IRQ 5 (MODE +E))) (DMA 0 (CHANNEL 0)) -(DMA 1 (CHANNEL 3)) +(DMA 1 (CHANNEL 1)) Here, note that: Port Acceptable Range Purpose ---- ---------------- ------- -IO 0 0x0220 - 0x0280 SB base address, I set to 0 just to be safe. +IO 0 0x0220 - 0x0280 SB base address, unused. IO 1 0x0530 - 0x0F48 MSS base address IO 2 0x0388 - 0x03F8 OPL3 base address IO 3 0x0300 - 0x0334 MPU base address IO 4 0x0100 - 0x0FFE card's own base address for its control I/O ports -The IRQ and DMA values can be any that considered acceptable for a +The IRQ and DMA values can be any that are considered acceptable for a MSS. Assuming you've got isapnp all happy, then you should be able to do something like the following (which matches up with the isapnp configuration above): -insmod mpu401 -insmod ad1848 -insmod opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=7 dma=0 dma2=3 -insmod opl3 io=0x388 - -Remember that the opl3sa2 module's io argument is for it's own control -port, which handles the card's master mixer for volume (on all cards), -and bass and treble (on SA3 and SAx cards). +modprobe mpu401 +modprobe ad1848 +modprobe opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=5 dma=0 dma2=1 +modprobe opl3 io=0x388 + +See the section "Automatic Module Loading" below for how to set up +/etc/modules.conf to automate this. + +An important thing to remember that the opl3sa2 module's io argument is +for it's own control port, which handles the card's master mixer for +volume (on all cards), and bass and treble (on SA3 cards). + + +Troubleshooting +--------------- If all goes well and you see no error messages, you should be able to start using the sound capabilities of your system. If you get an @@ -112,29 +183,27 @@ If you still cannot get the module to load, look at the contents of your system log file, usually /var/log/messages. If you see the -message "Unknown Yamaha audio controller version", then you have a -different chipset than I've encountered so far. Look for a line in -the log file that says "opl3sa2.c: chipset version = ". -If you want me to add support for your card, send me the number from -this line and any information you have on the make and chipset of your -sound card, and I should be able to work up a permanent fix. - -If you do not see the chipset version message, and none of the other -messages present in the system log are helpful, email me some details -and I'll try my best to help. +message "opl3sa2: Unknown Yamaha audio controller version", then you +have a different chipset version than I've encountered so far. Look +for all messages in the log file that start with "opl3sa2: " and see +if they provide any clues. If you do not see the chipset version +message, and none of the other messages present in the system log are +helpful, email me some details and I'll try my best to help. + + +Automatic Module Loading +------------------------ Lastly, if you're using modules and want to set up automatic module loading with kmod, the kernel module loader, here is the section I currently use in my modules.conf file: # Sound -alias char-major-14 opl3sa2 -pre-install opl3sa2 modprobe "-k" "ad1848" -post-install opl3sa2 modprobe "-k" "opl3" +alias sound-slot-0 opl3sa2 options opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=7 dma=0 dma2=3 options opl3 io=0x388 -That's all it currently takes to get an OPL3-SAx card working on my +That's all it currently takes to get an OPL3-SA3 card working on my system. Once again, if you have any other problems, email me at the address listed above. diff -u --recursive --new-file v2.4.1/linux/Documentation/sound/via82cxxx.txt linux/Documentation/sound/via82cxxx.txt --- v2.4.1/linux/Documentation/sound/via82cxxx.txt Tue Jun 20 07:52:36 2000 +++ linux/Documentation/sound/via82cxxx.txt Wed Dec 31 16:00:00 1969 @@ -1,176 +0,0 @@ - Via motherboard audio driver - Copyright 1999,2000 Jeff Garzik - -Driver software and documentation distributed under the GNU GENERAL -PUBLIC LICENSE (GPL) Version 2. See the "COPYING" file distributed with -this software for more info. - - - -Introduction ------------------------------------------------------------------------- -The via82cxxx audio driver found in the drivers/sound directory -of the kernel source tree is a PCI audio driver for audio chips -found on Via-based motherboards, such as the MVP4. - -Currently the driver exports the following features: - - * /dev/dsp and /dev/audio support - * 16-bit stereo PCM output channel - * AC97 mixer - -Please send bug reports to the mailing list linux-via@gtf.org. -To subscribe, e-mail majordomo@gtf.org with "subscribe linux-via" in the -body of the message. - - -Thanks ------------------------------------------------------------------------- -Via for providing e-mail support, specs, and NDA'd source code. - -MandrakeSoft for providing hacking time. - -AC97 mixer interface fixes and debugging by Ron Cemer - - - -Installation ------------------------------------------------------------------------- -If the driver is being statically compiled into the kernel, no -configuration should be necessary. - -If the driver is being compiled as a module, generally one line must -be added to your /etc/conf.modules (or /etc/modules.conf) file: - - alias sound via82cxxx_audio - - - -Driver notes ------------------------------------------------------------------------- -Two /proc pseudo-files provide diagnostic information. This is generally -not useful to most users. Power users can disable VIA_PROC_FS macro in the -driver source code, and remove the /proc support code. In any case, once -version 2.0.0 is released, the /proc support code will be disabled by -default. Available /proc pseudo-files: - - /proc/driver/via/0/info - /proc/driver/via/0/ac97 - -This driver by default supports all PCI audio devices which report -a vendor id of 0x1106, and a device id of 0x3058. Subsystem vendor -and device ids are not examined. - -Only supports a single sound chip, as this is a motherboard chipset. -Some architecture remains for multiple cards, feel free to submit -a patch to clean some of that up. Ideally, - -No consideration for SMP, this chipset is not known to be found on -any SMP motherboards. However, spin_locks must be used anyway in order -to handle interrupts correctly. - -GNU indent formatting options: -kr -i8 -pcs - - - -Tested Hardware ------------------------------------------------------------------------- -The following is an _incomplete_ list of motherboards supported by this -audio driver. If your motherboard (or notebook) is not listed here, -please e-mail the maintainer with details. - - AOpen MX59 Pro - Compaq Presario 1247 - - - -Random Developer Notes / Comments ------------------------------------------------------------------------- -Via has graciously donated e-mail support and source code to help further -the development of this driver. Their assistance has been invaluable -in the design and coding of the next major version of this driver. - -The Via audio chip apparently provides a second PCM scatter-gather -DMA channel just for FM data, but does not have a full hardware MIDI -processor. I haven't put much thought towards a solution here, but it -might involve using SoftOSS midi wave table, or simply disabling MIDI -support altogether and using the FM PCM channel as a second (input? output?) - - - -General To-do List (patches/suggestions welcome) ------------------------------------------------------------------------- -Recording support - -mmap support - -Other advanced ioctls - -Better docs - -Code review - -Native MIDI driver, as described above - - - -Known bugs (patches/suggestions welcome) ------------------------------------------------------------------------- -1) Volume too low on many systems. Workaround: use mixer program -such as xmixer to increase volume. - -2) RealPlayer output very scratchy. Workaround: use esd, and -configure RealPlayer to output to esd. - -3) Applications which attempt to open the sound device in read/write -mode (O_RDWR) will fail. This is incorrect OSS behavior, but since -this driver will eventually support recording as well as playback, -we will be able to (in the future) support even broken programs which -unconditionally use O_RDWR. - - - -Submitting a bug report ------------------------------------------------------------------------- -Describe the application you were using to play/record sound, and how -to reproduce the problem. - -Obtain the via-audio-diag diagnostics program from -http://gtf.org/garzik/drivers/via82cxxx/ and provide a dump of the -audio chip's registers while the problem is occurring. Sample command line: - ./via-audio-diag -aps > diag-output.txt - -Define "VIA_DEBUG" at the beginning of the driver, then capture and email -the kernel log output. This can be viewed in the system kernel log (if -enabled), or via the 'dmesg' program. - -If you wish to increase the size of the buffer displayed by 'dmesg', then -change the LOG_BUF_LEN macro at the top of linux/kernel/printk.c, recompile -your kernel, and pass the "-s " option to 'dmesg'. - - - -Change history ------------------------------------------------------------------------- -Version 1.1.7: -* Fix module unload bug where mixer device left registered - after driver exit - -Version 1.1.6: -* Rewrite via_set_rate to mimic ALSA basic AC97 rate setting -* Remove much dead code -* Complete spin_lock_irqsave -> spin_lock_irq conversion in via_dsp_ioctl -* Fix build problem in via_dsp_ioctl -* Optimize included headers to eliminate headers found in linux/drivers/sound - -Version 1.1.5: -* Disable some overly-verbose debugging code -* Remove unnecessary sound locks -* Fix some ioctls for better time resolution -* Begin spin_lock_irqsave -> spin_lock_irq conversion in via_dsp_ioctl - -Version 1.1.4: -* Completed rewrite of driver. Eliminated SoundBlaster compatibility - completely, and now uses the much-faster scatter-gather DMA engine. - - diff -u --recursive --new-file v2.4.1/linux/Documentation/usb/uhci.txt linux/Documentation/usb/uhci.txt --- v2.4.1/linux/Documentation/usb/uhci.txt Fri Jul 28 12:50:52 2000 +++ linux/Documentation/usb/uhci.txt Tue Feb 13 14:13:43 2001 @@ -33,7 +33,7 @@ great USB-October-Revolution started by GA, DF, and TS ;-) Since the concept is in no way UHCI dependent, we hope that it will also be -transfered to the OHCI-driver, so both drivers share a common API. +transferred to the OHCI-driver, so both drivers share a common API. 1.2. Advantages and disadvantages diff -u --recursive --new-file v2.4.1/linux/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt --- v2.4.1/linux/Documentation/usb/usb-serial.txt Sat Feb 3 19:51:21 2001 +++ linux/Documentation/usb/usb-serial.txt Thu Feb 8 16:30:40 2001 @@ -73,6 +73,11 @@ the port to use for the HotSync transfer. The "Generic" port can be used for other device communication, such as a PPP link. + If after pressing the sync button, nothing shows up in the system log, + try resetting the Visor, first a hot reset, and then a cold reset if + necessary. Some Visors need this before they can talk to the USB port + properly. + There is a webpage and mailing lists for this portion of the driver at: http://usbvisor.sourceforge.net/ @@ -103,22 +108,22 @@ Keyspan USA-series Serial Adapters - Single and Dual port adapters - driver uses Keyspan supplied + Single, Dual and Quad port adapters - driver uses Keyspan supplied firmware and is being developed with their support. - Driver isn't as far advanced as Keyspan PDA driver mentioned above. - Current status: - Things that work: - Firmware upload for USA-18X, USA-28, USA-28X, USA-19 and USA-19W - Simple character I/O fixed at 9600 baud on USA-19 only - - Things that don't: - Everything else. (for now...) + The USA-18X, USA-28X, USA-19, USA-19W and USA-49W are supported and + have been pretty throughly tested at various baud rates with 8-N-1 + character settings. Other character lengths and parity setups are + presently untested. + + The USA-28 isn't yet supported though doing so should be pretty + straightforward. Contact the maintainer if you require this + functionality. + + More information is available at: + http://www.linuxcare.com.au/hugh/keyspan.html - Big Things on the todo list: - Driver is in infancy, much functionality remains to be added - FTDI Single Port Serial Driver @@ -157,6 +162,7 @@ Belkin USB Serial Adapter F5U103 Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs. + The Peracom single port serial adapter also works with this driver. Current status: The following have been tested and work: @@ -210,6 +216,11 @@ The driver is generally working, though it still needs some more testing. It is derived from the Belkin USB Serial Adapter F5U103 driver and its TODO list is valid for this driver as well. + + This driver has also been found to work for other products, which have + the same Vendor ID but different Product IDs. Sitecom's U232-P25 + serial converter uses Product ID 0x230 and Vendor ID 0x711 and works with + this driver. Also, D-Link's DU-H3SP USB BAY also works with this driver. Generic Serial driver diff -u --recursive --new-file v2.4.1/linux/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST --- v2.4.1/linux/Documentation/video4linux/bttv/CARDLIST Sun Nov 12 20:47:19 2000 +++ linux/Documentation/video4linux/bttv/CARDLIST Mon Feb 19 14:43:36 2001 @@ -38,36 +38,50 @@ card=36 - Typhoon TView TV/FM Tuner card=37 - PixelView PlayTV pro card=38 - TView99 CPH063 - card=39 - Pinnacle PCTV Rave + card=39 - Pinnacle PCTV Studio/Rave card=40 - STB2 card=41 - AVerMedia TVPhone 98 card=42 - ProVideo PV951 card=43 - Little OnAir TV card=44 - Sigma TVII-FM card=45 - MATRIX-Vision MV-Delta 2 - card=46 - Zoltrix Genie TV + card=46 - Zoltrix Genie TV/FM card=47 - Terratec TV/Radio+ card=48 - Dynalink Magic TView card=49 - GV-BCTV3 card=50 - Prolink PV-BT878P+4E (PixelView PlayTV PAK) card=51 - Eagle Wireless Capricorn2 (bt878A) - card=52 - Pinnacle Studio PCTV Pro - card=53 - Typhoon TView RDS + card=52 - Pinnacle PCTV Studio Pro + card=53 - Typhoon TView RDS / FM Stereo + card=54 - Livetec 9415 TV + card=55 - BESTBUY Easy TV + card=56 - FlyVideo '98/FM + card=57 - GrandTec 'Grand Video Capture' + card=58 - Phoebe TV Master Only (No FM) tuner.o - type=0 - Temic PAL + type=0 - Temic PAL (4002 FH5) type=1 - Philips PAL_I type=2 - Philips NTSC type=3 - Philips SECAM type=4 - NoTuner type=5 - Philips PAL - type=6 - Temic NTSC - type=7 - Temic PAL_I - type=8 - Temic 4036 FY5 NTSC + type=6 - Temic NTSC (4032 FY5) + type=7 - Temic PAL_I (4062 FY5) + type=8 - Temic NTSC (4036 FY5) type=9 - Alps HSBH1 type=10 - Alps TSBE1 type=11 - Alps TSBB5 type=12 - Alps TSBE5 type=13 - Alps TSBC5 - type=14 - Temic 4006FH5 + type=14 - Temic PAL_I (4006FH5) type=15 - Alps TSCH6 + type=16 - Temic PAL_DK (4016 FY5) + type=17 - Philips NTSC_M (MK2) + type=18 - Temic PAL_I (4066 FY5) + type=19 - Temic PAL* auto (4006 FN5) + type=20 - Temic PAL (4009 FR5) + type=21 - Temic NTSC (4039 FR5) + type=22 - Temic PAL/SECAM multi (4046 FM5) + type=23 - Philips PAL_DK + type=24 - Philips PAL/SECAM multi (FQ1216ME) diff -u --recursive --new-file v2.4.1/linux/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options --- v2.4.1/linux/Documentation/video4linux/bttv/Insmod-options Sat Dec 30 11:23:13 2000 +++ linux/Documentation/video4linux/bttv/Insmod-options Mon Feb 19 14:43:36 2001 @@ -30,6 +30,12 @@ default is 2. gbufsize= size of capture buffers. default and maximum value is 0x208000 (~2MB) + no_overlay=0 Enable overlay on broken hardware. There + are some chipsets (SIS for example) which + are known to have problems with the PCI DMA + push used by bttv. bttv will disable overlay + by default on this hardware to avoid crashes. + With this insmod option you can override this. bttv_gpio=0/1 gpiomask= @@ -48,6 +54,8 @@ debug=1 print some debug info to the syslog type=n type of the tuner chip. n as follows: see CARDLIST for a complete list. + pal=[bdgil] select PAL variant (used for some tuners + only, important for the audio carrier). tvmixer.o registers a mixer device for the TV card's volume/bass/treble diff -u --recursive --new-file v2.4.1/linux/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README --- v2.4.1/linux/Documentation/video4linux/bttv/README Sat Dec 30 11:23:13 2000 +++ linux/Documentation/video4linux/bttv/README Mon Feb 19 14:43:36 2001 @@ -16,9 +16,10 @@ kernel, download it from: http://www2.lm-sensors.nu/~lm78/download.html -You'll need at least these i2c config options for bttv: +You'll need at least these config options for bttv: CONFIG_I2C=m CONFIG_I2C_ALGOBIT=m +CONFIG_VIDEO_DEV=m The latest bttv version is available here: http://www.strusel007.de/linux/bttv/ @@ -50,12 +51,8 @@ Make bttv work with your card ----------------------------- -Of course you have to load the modules as very first thing. The -separate bttv bundle comes with a script called "update". I use this -one to load a new version while doing driver hacking. You can use it -too, but check the module arguments first. They work for my setup, -and probably do *not* for yours. Another way is to setup your -/etc/modules.conf file and let kmod load the modules. See also: +Setup your /etc/modules.conf file and let kmod load the modules. +See also: Modules.conf: some sample entries for /etc/modules.conf Insmod-options: list of all insmod options available for bttv and @@ -68,15 +65,45 @@ to load them automagically by calling request_module() now, but this obviously works only with kmod enabled. +If bttv takes very long to load (happens sometimes with the cheap +cards which have no tuner), try adding this to your modules.conf: + options i2c-algo-bit bit_test=1 + The most important insmod option for bttv is "card=n" to select the -correct card type. If you get video but no sound you've very likely -specified the wrong (or no) card type. A list of supported cards is -in CARDLIST. +correct card type in case the autodetection does'nt work. If you get +video but no sound you've very likely specified the wrong (or no) +card type. A list of supported cards is in CARDLIST. If your card isn't listed in CARDLIST or if you have trouble making audio work, you should read the Sound-FAQ. +Autodetecting cards +------------------- + +bttv uses the PCI Subsystem ID to autodetect the card type. lspci lists +the Subsystem ID in the second line, looks like this: + +00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02) + Subsystem: Hauppauge computer works Inc. WinTV/GO + Flags: bus master, medium devsel, latency 32, IRQ 5 + Memory at e2000000 (32-bit, prefetchable) [size=4K] + +only bt878-based cards can have a subsystem ID (which does not mean +that every card really has one). bt848 cards can't have a Subsystem +ID and therefore can't be autodetected. There is a list with the ID's +in bttv-cards.c (in case you are intrested or want to mail patches +with updates). + +Old driver versions used to have a heuristic which could identify some +bt848-based cards. It worked for Hauppauge and Miro cards in most +cases (simply because these where the first cards available on the +market), but misdetected other bt848 cards. That code is gone now for +exactly this reason, the misdetection confused lots of people. If you +have a old Hauppauge or Miro card, you'll have to load the driver with +card=1 or card=2 these days. + + Still doesn't work? ------------------- @@ -87,10 +114,12 @@ yourself (patches very welcome of course...) You know: The linux slogan is "Do it yourself". -There is a mailing list: video4linux-list@redhat.com. If you have -trouble with some specific TV card, try to ask there instead of -mailing me directly. The chance that someone with the same card -listens there is much higher... +There is a mailing list: video4linux-list@redhat.com. +https://listman.redhat.com/mailman/listinfo/video4linux-list + +If you have trouble with some specific TV card, try to ask there +instead of mailing me directly. The chance that someone with the +same card listens there is much higher... For problems with sound: There are alot of different systems used for TV sound all over the world. And there are also different chips diff -u --recursive --new-file v2.4.1/linux/Documentation/video4linux/bttv/Sound-FAQ linux/Documentation/video4linux/bttv/Sound-FAQ --- v2.4.1/linux/Documentation/video4linux/bttv/Sound-FAQ Sun Nov 12 20:47:19 2000 +++ linux/Documentation/video4linux/bttv/Sound-FAQ Mon Feb 19 14:43:36 2001 @@ -79,10 +79,12 @@ What you have to do is figure out the correct values for gpiomask and the audiomux array. If you have Windows and the drivers four your card installed, you might to check out if you can read these registers -values used by the windows driver. A tool to do this is available -from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil (doesn't -work with bt878 boards according to some reports I received). You -might also dig around in the *.ini files of the Windows applications. +values used by the windows driver. A tool to do this is available from +ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil, but it does'nt +work with bt878 boards according to some reports I received. Another +one is available from http://www.kki.net.pl/~borgx/bTV.html. + +You might also dig around in the *.ini files of the Windows applications. You can have a look at the board to see which of the gpio pins are connected at all and then start trial-and-error ... diff -u --recursive --new-file v2.4.1/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.1/linux/MAINTAINERS Sat Feb 3 19:51:21 2001 +++ linux/MAINTAINERS Mon Feb 19 10:18:18 2001 @@ -857,6 +857,14 @@ M: pavel@atrey.karlin.mff.cuni.cz S: Maintained +NETWORK DEVICE DRIVERS +P: Andrew Morton +M: andrewm@uow.edu.au +P: Jeff Garzik +M: jgarzik@mandrakesoft.com +L: linux-net@vger.kernel.org +S: Maintained + NETWORKING [GENERAL] P: Networking Team M: netdev@oss.sgi.com diff -u --recursive --new-file v2.4.1/linux/Makefile linux/Makefile --- v2.4.1/linux/Makefile Sat Feb 3 19:51:21 2001 +++ linux/Makefile Wed Feb 21 16:54:15 2001 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 1 +SUBLEVEL = 2 EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -110,7 +110,7 @@ export SVGA_MODE = -DSVGA_MODE=NORMAL_VGA # -# if you want the RAM disk device, define this to be the size in blocks. +# If you want the RAM disk device, define this to be the size in blocks. # This is i386 specific. # @@ -138,9 +138,9 @@ DRIVERS-$(CONFIG_ISDN) += drivers/isdn/isdn.a DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.o DRIVERS-$(CONFIG_APPLETALK) += drivers/net/appletalk/appletalk.o -DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.a +DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.o DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.o -DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnet.a +DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnetdrv.o DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.4.1/linux/arch/alpha/kernel/Makefile Sat Feb 3 19:51:21 2001 +++ linux/arch/alpha/kernel/Makefile Fri Feb 9 11:38:01 2001 @@ -30,9 +30,7 @@ obj-y += console.o endif - obj-$(CONFIG_SMP) += smp.o irq_smp.o - obj-$(CONFIG_PCI) += pci.o pci_iommu.o ifdef CONFIG_ALPHA_GENERIC @@ -76,7 +74,7 @@ endif obj-$(CONFIG_ALPHA_EIGER) += sys_eiger.o -obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o +obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o pci-noop.o obj-$(CONFIG_ALPHA_MIATA) += sys_miata.o obj-$(CONFIG_ALPHA_MIKASA) += sys_mikasa.o obj-$(CONFIG_ALPHA_NAUTILUS) += sys_nautilus.o diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.4.1/linux/arch/alpha/kernel/alpha_ksyms.c Sun Nov 12 19:27:11 2000 +++ linux/arch/alpha/kernel/alpha_ksyms.c Tue Feb 13 14:56:41 2001 @@ -98,9 +98,13 @@ EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(__memsetw); EXPORT_SYMBOL(__constant_c_memset); +EXPORT_SYMBOL(copy_page); +EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(__direct_map_base); EXPORT_SYMBOL(__direct_map_size); + +#ifdef CONFIG_PCI EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); @@ -108,6 +112,7 @@ EXPORT_SYMBOL(pci_map_sg); EXPORT_SYMBOL(pci_unmap_sg); EXPORT_SYMBOL(pci_dma_supported); +#endif EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); @@ -166,6 +171,7 @@ EXPORT_SYMBOL(__up_wakeup); EXPORT_SYMBOL(down); EXPORT_SYMBOL(down_interruptible); +EXPORT_SYMBOL(down_trylock); EXPORT_SYMBOL(up); EXPORT_SYMBOL(__down_read_failed); EXPORT_SYMBOL(__down_write_failed); diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.4.1/linux/arch/alpha/kernel/irq.c Fri Nov 17 08:47:05 2000 +++ linux/arch/alpha/kernel/irq.c Fri Feb 9 11:29:44 2001 @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/irq_alpha.c linux/arch/alpha/kernel/irq_alpha.c --- v2.4.1/linux/arch/alpha/kernel/irq_alpha.c Fri Aug 4 16:15:38 2000 +++ linux/arch/alpha/kernel/irq_alpha.c Tue Feb 13 14:13:43 2001 @@ -18,7 +18,7 @@ unsigned long __irq_attempt[NR_IRQS]; #endif -/* Hack minimum IPL during interupt processing for broken hardware. */ +/* Hack minimum IPL during interrupt processing for broken hardware. */ #ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK int __min_ipl; #endif diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.4.1/linux/arch/alpha/kernel/osf_sys.c Sat Feb 3 19:51:21 2001 +++ linux/arch/alpha/kernel/osf_sys.c Fri Feb 9 11:29:44 2001 @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -74,8 +74,10 @@ mm = current->mm; mm->end_code = bss_start + bss_len; mm->brk = bss_start + bss_len; +#if 0 printk("set_program_attributes(%lx %lx %lx %lx)\n", text_start, text_len, bss_start, bss_len); +#endif unlock_kernel(); return 0; } diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/pci-noop.c linux/arch/alpha/kernel/pci-noop.c --- v2.4.1/linux/arch/alpha/kernel/pci-noop.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/pci-noop.c Fri Feb 9 11:38:01 2001 @@ -0,0 +1,104 @@ +/* + * linux/arch/alpha/kernel/pci-noop.c + * + * Stub PCI interfaces for Jensen-specific kernels. + */ + +#include +#include +#include +#include +#include + +#include "proto.h" + + +/* + * The PCI controler list. + */ + +struct pci_controler *hose_head, **hose_tail = &hose_head; +struct pci_controler *pci_isa_hose; + + +struct pci_controler * __init +alloc_pci_controler(void) +{ + struct pci_controler *hose; + + hose = alloc_bootmem(sizeof(*hose)); + + *hose_tail = hose; + hose_tail = &hose->next; + + return hose; +} + +struct resource * __init +alloc_resource(void) +{ + struct resource *res; + + res = alloc_bootmem(sizeof(*res)); + + return res; +} + +asmlinkage long +sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn) +{ + struct pci_controler *hose; + struct pci_dev *dev; + + /* from hose or from bus.devfn */ + if (which & IOBASE_FROM_HOSE) { + for (hose = hose_head; hose; hose = hose->next) + if (hose->index == bus) + break; + if (!hose) + return -ENODEV; + } else { + /* Special hook for ISA access. */ + if (bus == 0 && dfn == 0) + hose = pci_isa_hose; + else + return -ENODEV; + } + + switch (which & ~IOBASE_FROM_HOSE) { + case IOBASE_HOSE: + return hose->index; + case IOBASE_SPARSE_MEM: + return hose->sparse_mem_base; + case IOBASE_DENSE_MEM: + return hose->dense_mem_base; + case IOBASE_SPARSE_IO: + return hose->sparse_io_base; + case IOBASE_DENSE_IO: + return hose->dense_io_base; + case IOBASE_ROOT_BUS: + return hose->bus->number; + } + + return -EOPNOTSUPP; +} + +asmlinkage long +sys_pciconfig_read(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, void *buf) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + else + return -ENODEV; +} + +asmlinkage long +sys_pciconfig_write(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, void *buf) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + else + return -ENODEV; +} diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.4.1/linux/arch/alpha/kernel/process.c Tue Sep 5 13:50:02 2000 +++ linux/arch/alpha/kernel/process.c Fri Feb 9 11:29:44 2001 @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -416,22 +416,20 @@ * Don't do this at home. */ asmlinkage int -sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs regs) +sys_execve(char *ufilename, char **argv, char **envp, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs regs) { int error; - char * filename; + char *filename; - lock_kernel(); - filename = getname((char *) a0); + filename = getname(ufilename); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char **) a1, (char **) a2, ®s); + error = do_execve(filename, argv, envp, ®s); putname(filename); out: - unlock_kernel(); return error; } diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v2.4.1/linux/arch/alpha/kernel/ptrace.c Mon Jun 19 17:59:32 2000 +++ linux/arch/alpha/kernel/ptrace.c Fri Feb 9 11:29:44 2001 @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.4.1/linux/arch/alpha/kernel/setup.c Tue Jan 2 16:45:37 2001 +++ linux/arch/alpha/kernel/setup.c Fri Feb 9 11:29:44 2001 @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/smc37c669.c linux/arch/alpha/kernel/smc37c669.c --- v2.4.1/linux/arch/alpha/kernel/smc37c669.c Mon Jun 19 17:59:32 2000 +++ linux/arch/alpha/kernel/smc37c669.c Fri Feb 9 11:29:44 2001 @@ -3,7 +3,7 @@ */ #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/smc37c93x.c linux/arch/alpha/kernel/smc37c93x.c --- v2.4.1/linux/arch/alpha/kernel/smc37c93x.c Sat Nov 27 15:42:54 1999 +++ linux/arch/alpha/kernel/smc37c93x.c Fri Feb 9 11:29:44 2001 @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.4.1/linux/arch/alpha/kernel/smp.c Tue Jan 2 16:45:37 2001 +++ linux/arch/alpha/kernel/smp.c Tue Feb 13 14:13:43 2001 @@ -837,7 +837,7 @@ atomic_set(&data.unstarted_count, smp_num_cpus - 1); atomic_set(&data.unfinished_count, smp_num_cpus - 1); - /* Aquire the smp_call_function_data mutex. */ + /* Acquire the smp_call_function_data mutex. */ if (pointer_lock(&smp_call_function_data, &data, retry)) return -EBUSY; diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c --- v2.4.1/linux/arch/alpha/kernel/sys_ruffian.c Mon Nov 27 17:50:12 2000 +++ linux/arch/alpha/kernel/sys_ruffian.c Thu Feb 8 12:56:29 2001 @@ -92,14 +92,80 @@ #endif } +/* + * Interrupt routing: + * + * Primary bus + * IdSel INTA INTB INTC INTD + * 21052 13 - - - - + * SIO 14 23 - - - + * 21143 15 44 - - - + * Slot 0 17 43 42 41 40 + * + * Secondary bus + * IdSel INTA INTB INTC INTD + * Slot 0 8 (18) 19 18 17 16 + * Slot 1 9 (19) 31 30 29 28 + * Slot 2 10 (20) 27 26 25 24 + * Slot 3 11 (21) 39 38 37 36 + * Slot 4 12 (22) 35 34 33 32 + * 53c875 13 (23) 20 - - - + * + */ + static int __init ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { - /* We don't know anything about the PCI routing, so leave - the IRQ unchanged. */ - return dev->irq; + static char irq_tab[11][5] __initdata = { + /*INT INTA INTB INTC INTD */ + {-1, -1, -1, -1, -1}, /* IdSel 13, 21052 */ + {-1, -1, -1, -1, -1}, /* IdSel 14, SIO */ + {44, 44, 44, 44, 44}, /* IdSel 15, 21143 */ + {-1, -1, -1, -1, -1}, /* IdSel 16, none */ + {43, 43, 42, 41, 40}, /* IdSel 17, 64-bit slot */ + /* the next 6 are actually on PCI bus 1, across the bridge */ + {19, 19, 18, 17, 16}, /* IdSel 8, slot 0 */ + {31, 31, 30, 29, 28}, /* IdSel 9, slot 1 */ + {27, 27, 26, 25, 24}, /* IdSel 10, slot 2 */ + {39, 39, 38, 37, 36}, /* IdSel 11, slot 3 */ + {35, 35, 34, 33, 32}, /* IdSel 12, slot 4 */ + {20, 20, 20, 20, 20}, /* IdSel 13, 53c875 */ + }; + const long min_idsel = 13, max_idsel = 23, irqs_per_slot = 5; + return COMMON_TABLE_LOOKUP; } +static u8 __init +ruffian_swizzle(struct pci_dev *dev, u8 *pinp) +{ + int slot, pin = *pinp; + + if (dev->bus->number == 0) { + slot = PCI_SLOT(dev->devfn); + } + /* Check for the built-in bridge. */ + else if (PCI_SLOT(dev->bus->self->devfn) == 13) { + slot = PCI_SLOT(dev->devfn) + 10; + } + else + { + /* Must be a card-based bridge. */ + do { + if (PCI_SLOT(dev->bus->self->devfn) == 13) { + slot = PCI_SLOT(dev->devfn) + 10; + break; + } + pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); + + /* Move up the chain of bridges. */ + dev = dev->bus->self; + /* Slot of the next bridge. */ + slot = PCI_SLOT(dev->devfn); + } while (dev->bus->self); + } + *pinp = pin; + return slot; +} #ifdef BUILDING_FOR_MILO /* @@ -164,6 +230,6 @@ init_pci: cia_init_pci, kill_arch: ruffian_kill_arch, pci_map_irq: ruffian_map_irq, - pci_swizzle: common_swizzle, + pci_swizzle: ruffian_swizzle, }; ALIAS_MV(ruffian) diff -u --recursive --new-file v2.4.1/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.4.1/linux/arch/alpha/kernel/traps.c Mon Jun 19 17:59:33 2000 +++ linux/arch/alpha/kernel/traps.c Thu Feb 8 12:56:29 2001 @@ -1093,7 +1093,9 @@ { /* We only get here for OSF system calls, minus #112; the rest go to sys_ni_syscall. */ +#if 0 printk("", regs.r0, a0, a1, a2); +#endif return -ENOSYS; } diff -u --recursive --new-file v2.4.1/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile --- v2.4.1/linux/arch/alpha/lib/Makefile Sat Dec 30 11:13:36 2000 +++ linux/arch/alpha/lib/Makefile Thu Feb 8 12:56:29 2001 @@ -42,6 +42,8 @@ $(ev6)strncpy_from_user.o \ $(ev67)strlen_user.o \ $(ev6)csum_ipv6_magic.o \ + $(ev6)clear_page.o \ + $(ev6)copy_page.o \ strcasecmp.o \ fpreg.o \ callback_srm.o srm_puts.o srm_printk.o diff -u --recursive --new-file v2.4.1/linux/arch/alpha/lib/clear_page.S linux/arch/alpha/lib/clear_page.S --- v2.4.1/linux/arch/alpha/lib/clear_page.S Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/clear_page.S Thu Feb 8 12:56:29 2001 @@ -0,0 +1,39 @@ +/* + * arch/alpha/lib/clear_page.S + * + * Zero an entire page. + */ + + .text + .align 4 + .global clear_page + .ent clear_page +clear_page: + .prologue 0 + + lda $0,128 + nop + unop + nop + +1: stq $31,0($16) + stq $31,8($16) + stq $31,16($16) + stq $31,24($16) + + stq $31,32($16) + stq $31,40($16) + stq $31,48($16) + subq $0,1,$0 + + stq $31,56($16) + addq $16,64,$16 + unop + bne $0,1b + + ret + nop + unop + nop + + .end clear_page diff -u --recursive --new-file v2.4.1/linux/arch/alpha/lib/copy_page.S linux/arch/alpha/lib/copy_page.S --- v2.4.1/linux/arch/alpha/lib/copy_page.S Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/copy_page.S Thu Feb 8 12:56:29 2001 @@ -0,0 +1,49 @@ +/* + * arch/alpha/lib/copy_page.S + * + * Copy an entire page. + */ + + .text + .align 4 + .global copy_page + .ent copy_page +copy_page: + .prologue 0 + + lda $18,128 + nop + unop + nop + +1: ldq $0,0($17) + ldq $1,8($17) + ldq $2,16($17) + ldq $3,24($17) + + ldq $4,32($17) + ldq $5,40($17) + ldq $6,48($17) + ldq $7,56($17) + + stq $0,0($16) + subq $18,1,$18 + stq $1,8($16) + addq $17,64,$17 + + stq $2,16($16) + stq $3,24($16) + stq $4,32($16) + stq $5,40($16) + + stq $6,48($16) + stq $7,56($16) + addq $16,64,$16 + bne $18, 1b + + ret + nop + unop + nop + + .end copy_page diff -u --recursive --new-file v2.4.1/linux/arch/alpha/lib/ev6-clear_page.S linux/arch/alpha/lib/ev6-clear_page.S --- v2.4.1/linux/arch/alpha/lib/ev6-clear_page.S Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/ev6-clear_page.S Thu Feb 8 12:56:29 2001 @@ -0,0 +1,54 @@ +/* + * arch/alpha/lib/ev6-clear_page.S + * + * Zero an entire page. + */ + + .text + .align 4 + .global clear_page + .ent clear_page +clear_page: + .prologue 0 + + lda $0,128 + lda $1,125 + addq $16,64,$2 + addq $16,128,$3 + + addq $16,192,$17 + wh64 ($16) + wh64 ($2) + wh64 ($3) + +1: wh64 ($17) + stq $31,0($16) + subq $0,1,$0 + subq $1,1,$1 + + stq $31,8($16) + stq $31,16($16) + addq $17,64,$2 + nop + + stq $31,24($16) + stq $31,32($16) + cmovgt $1,$2,$17 + nop + + stq $31,40($16) + stq $31,48($16) + nop + nop + + stq $31,56($16) + addq $16,64,$16 + nop + bne $0,1b + + ret + nop + nop + nop + + .end clear_page diff -u --recursive --new-file v2.4.1/linux/arch/alpha/lib/ev6-copy_page.S linux/arch/alpha/lib/ev6-copy_page.S --- v2.4.1/linux/arch/alpha/lib/ev6-copy_page.S Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/ev6-copy_page.S Thu Feb 8 12:56:29 2001 @@ -0,0 +1,203 @@ +/* + * arch/alpha/lib/ev6-copy_page.S + * + * Copy an entire page. + */ + +/* The following comparison of this routine vs the normal copy_page.S + was written by an unnamed ev6 hardware designer and forwarded to me + via Steven Hobbs . + + First Problem: STQ overflows. + ----------------------------- + + It would be nice if EV6 handled every resource overflow efficiently, + but for some it doesn't. Including store queue overflows. It causes + a trap and a restart of the pipe. + + To get around this we sometimes use (to borrow a term from a VSSAD + researcher) "aeration". The idea is to slow the rate at which the + processor receives valid instructions by inserting nops in the fetch + path. In doing so, you can prevent the overflow and actually make + the code run faster. You can, of course, take advantage of the fact + that the processor can fetch at most 4 aligned instructions per cycle. + + I inserted enough nops to force it to take 10 cycles to fetch the + loop code. In theory, EV6 should be able to execute this loop in + 9 cycles but I was not able to get it to run that fast -- the initial + conditions were such that I could not reach this optimum rate on + (chaotic) EV6. I wrote the code such that everything would issue + in order. + + Second Problem: Dcache index matches. + ------------------------------------- + + If you are going to use this routine on random aligned pages, there + is a 25% chance that the pages will be at the same dcache indices. + This results in many nasty memory traps without care. + + The solution is to schedule the prefetches to avoid the memory + conflicts. I schedule the wh64 prefetches farther ahead of the + read prefetches to avoid this problem. + + Third Problem: Needs more prefetching. + -------------------------------------- + + In order to improve the code I added deeper prefetching to take the + most advantage of EV6's bandwidth. + + I also prefetched the read stream. Note that adding the read prefetch + forced me to add another cycle to the inner-most kernel - up to 11 + from the original 8 cycles per iteration. We could improve performance + further by unrolling the loop and doing multiple prefetches per cycle. + + I think that the code below will be very robust and fast code for the + purposes of copying aligned pages. It is slower when both source and + destination pages are in the dcache, but it is my guess that this is + less important than the dcache miss case. */ + + + .text + .align 4 + .global copy_page + .ent copy_page +copy_page: + .prologue 0 + + /* Prefetch 5 read cachelines; write-hint 10 cache lines. */ + wh64 ($16) + ldl $31,0($17) + ldl $31,64($17) + lda $1,1*64($16) + + wh64 ($1) + ldl $31,128($17) + ldl $31,192($17) + lda $1,2*64($16) + + wh64 ($1) + ldl $31,256($17) + lda $18,118 + lda $1,3*64($16) + + wh64 ($1) + nop + lda $1,4*64($16) + lda $2,5*64($16) + + wh64 ($1) + wh64 ($2) + lda $1,6*64($16) + lda $2,7*64($16) + + wh64 ($1) + wh64 ($2) + lda $1,8*64($16) + lda $2,9*64($16) + + wh64 ($1) + wh64 ($2) + lda $19,10*64($16) + nop + + /* Main prefetching/write-hinting loop. */ +1: ldq $0,0($17) + ldq $1,8($17) + unop + unop + + unop + unop + ldq $2,16($17) + ldq $3,24($17) + + ldq $4,32($17) + ldq $5,40($17) + unop + unop + + unop + unop + ldq $6,48($17) + ldq $7,56($17) + + ldl $31,320($17) + unop + unop + unop + + /* This gives the extra cycle of aeration above the minimum. */ + unop + unop + unop + unop + + wh64 ($19) + unop + unop + unop + + stq $0,0($16) + subq $18,1,$18 + stq $1,8($16) + unop + + unop + stq $2,16($16) + addq $17,64,$17 + stq $3,24($16) + + stq $4,32($16) + stq $5,40($16) + addq $19,64,$19 + unop + + stq $6,48($16) + stq $7,56($16) + addq $16,64,$16 + bne $18, 1b + + /* Prefetch the final 5 cache lines of the read stream. */ + lda $18,10 + ldl $31,320($17) + ldl $31,384($17) + ldl $31,448($17) + + ldl $31,512($17) + ldl $31,576($17) + nop + nop + + /* Non-prefetching, non-write-hinting cleanup loop for the + final 10 cache lines. */ +2: ldq $0,0($17) + ldq $1,8($17) + ldq $2,16($17) + ldq $3,24($17) + + ldq $4,32($17) + ldq $5,40($17) + ldq $6,48($17) + ldq $7,56($17) + + stq $0,0($16) + subq $18,1,$18 + stq $1,8($16) + addq $17,64,$17 + + stq $2,16($16) + stq $3,24($16) + stq $4,32($16) + stq $5,40($16) + + stq $6,48($16) + stq $7,56($16) + addq $16,64,$16 + bne $18, 2b + + ret + nop + unop + nop + + .end copy_page diff -u --recursive --new-file v2.4.1/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.4.1/linux/arch/arm/Makefile Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/Makefile Thu Feb 8 16:32:44 2001 @@ -12,25 +12,18 @@ # # Copyright (C) 1995-2000 by Russell King -OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S -CPP := $(CC) -E -LINKFLAGS := -p -X -T arch/arm/vmlinux.lds -ARCHCC := $(word 1,$(CC)) - -AFLAGS += -mno-fpu -CFLAGS_PIPE := -pipe -CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) -msoft-float +LINKFLAGS :=-p -X -T arch/arm/vmlinux.lds +GZFLAGS :=-9 +CFLAGS +=-fno-common -pipe ifdef CONFIG_FRAME_POINTER -CFLAGS := $(CFLAGS:-fomit-frame-pointer=) +CFLAGS :=$(CFLAGS:-fomit-frame-pointer=) endif ifdef CONFIG_DEBUG_INFO -CFLAGS += -g +CFLAGS +=-g endif -GZFLAGS = -9 - # Ensure this is ld "2.9.4" or later NEW_LINKER := $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?) @@ -40,61 +33,42 @@ @false endif -# GCC 2.7 uses different options to later compilers; sort out which we have -NEW_GCC := $(shell $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; echo $$?) - -# -# select flags depending on the compiler +# Select CPU dependent flags. Note that order of declaration is important; +# the options further down the list override previous items. # -ifneq ($(NEW_GCC),0) -CFLAGS += -mshort-load-bytes -CFLAGS_PROC_CPU_26 := -mcpu=arm3 -mapcs-26 -Os -CFLAGS_PROC_CPU_32v3 := -march=armv3 -CFLAGS_PROC_CPU_32v4 := -march=armv4 -else -CFLAGS += -DNO_TEXT_SECTIONS -CFLAGS_PROC_CPU_26 := -m3 -CFLAGS_PROC_CPU_32v3 := -m6 -CFLAGS_PROC_CPU_32v4 := -m6 -endif +apcs-$(CONFIG_CPU_26) :=-mapcs-26 -mcpu=arm3 -Os +apcs-$(CONFIG_CPU_32) :=-mapcs-32 + +arch-$(CONFIG_CPU_32v3) :=-march=armv3 +arch-$(CONFIG_CPU_32v4) :=-march=armv4 +arch-$(CONFIG_CPU_32v5) :=-march=armv5 + +proc-$(CONFIG_CPU_32v3) :=-marmv3m +proc-$(CONFIG_CPU_32v4) :=-marmv4 +proc-$(CONFIG_CPU_32v5) :=-marmv5 + +tune-$(CONFIG_CPU_ARM610) :=-mtune=arm610 +tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710 +tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi +tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi +tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 +tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 + +CFLAGS += $(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float +AFLAGS += $(apcs-y) $(proc-y) -mno-fpu + +LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) -# -# Select CPU dependent flags -# ifeq ($(CONFIG_CPU_26),y) - PROCESSOR = armo - TEXTADDR = 0x02080000 - CFLAGS += $(CFLAGS_PROC_CPU_26) - AFLAGS += -mapcs-26 +PROCESSOR = armo +TEXTADDR = 0x02080000 endif ifeq ($(CONFIG_CPU_32),y) - PROCESSOR = armv - TEXTADDR = 0xC0008000 - ifeq ($(CONFIG_CPU_32v4),y) - CFLAGS += $(CFLAGS_PROC_CPU_32v4) - AFLAGS += -mapcs-32 -marmv4 - else - CFLAGS += $(CFLAGS_PROC_CPU_32v3) - AFLAGS += -mapcs-32 -marmv3m - endif - - opt-$(CONFIG_CPU_ARM6) := -mtune=arm6 - opt-$(CONFIG_CPU_ARM7) := -mtune=arm7 - opt-$(CONFIG_CPU_ARM720) := -mtune=arm7tdmi - opt-$(CONFIG_CPU_ARM920) := -mtune=arm9tdmi - opt-$(CONFIG_CPU_SA110) := -mtune=strongarm110 - opt-$(CONFIG_CPU_SA1100) := -mtune=strongarm110 - - ifneq ($(NEW_GCC),0) - CFLAGS += $(opt-y) - endif +PROCESSOR = armv +TEXTADDR = 0xC0008000 endif -LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) - -export LIBGCC MACHINE PROCESSOR TEXTADDR GZFLAGS - ifeq ($(CONFIG_ARCH_ARCA5K),y) MACHINE = arc endif @@ -132,6 +106,10 @@ endif ifeq ($(CONFIG_ARCH_SA1100),y) +ifeq ($(CONFIG_SA1111),y) +# SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memory +TEXTADDR = 0xc0208000 +endif MACHINE = sa1100 endif @@ -143,6 +121,13 @@ MACHINE = integrator endif +ifeq ($(CONFIG_ARCH_CLPS711X),y) +TEXTADDR = 0xc0018000 +MACHINE = clps711x +endif + +export LIBGCC MACHINE PROCESSOR TEXTADDR GZFLAGS + # Only set INCDIR if its not already defined above # Grr, ?= doesn't work as all the other assignment operators do. Make bug? ifeq ($(origin INCDIR), undefined) @@ -158,8 +143,7 @@ HEAD := arch/arm/kernel/head-$(PROCESSOR).o \ arch/arm/kernel/init_task.o -SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib \ - arch/arm/nwfpe +SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(LIBGCC) @@ -167,14 +151,6 @@ LIBS := arch/arm/nwfpe/math-emu.o $(LIBS) endif -ifeq ($(CONFIG_ARCH_ACORN),y) -SUBDIRS += drivers/acorn -DRIVERS += drivers/acorn/block/acorn-block.a -DRIVERS += drivers/acorn/char/acorn-char.o -DRIVERS += drivers/acorn/net/acorn-net.o -DRIVERS += drivers/acorn/scsi/acorn-scsi.a -endif - ifeq ($(CONFIG_ARCH_CLPS7500),y) SUBDIRS += drivers/acorn/char DRIVERS += drivers/acorn/char/acorn-char.o @@ -230,6 +206,7 @@ Img:; @$(MAKEBOOT) Image i:; @$(MAKEBOOT) install zi:; @$(MAKEBOOT) zinstall +bp:; @$(MAKEBOOT) bootpImage # # Configuration targets. Use these to select a @@ -237,9 +214,10 @@ CFGS= a5k_config ebsa110_config \ footbridge_config rpc_config \ brutus_config victor_config \ - empeg_config thinclient_config \ + empeg_config graphicsclient_config \ assabet_config lart_config \ - cerf_config lusl7200_config + cerf_config lusl7200_config \ + sherman_config pangolin_config $(CFGS): @( \ diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile --- v2.4.1/linux/arch/arm/boot/Makefile Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/boot/Makefile Thu Feb 8 16:32:44 2001 @@ -83,15 +83,18 @@ ZRELADDR = 0xc0008000 ifeq ($(CONFIG_SA1100_VICTOR),y) ZTEXTADDR = 0x00002000 - ZBSSADDR = 0xc0100000 + ZBSSADDR = 0xc0200000 endif ifeq ($(CONFIG_SA1100_SHERMAN),y) ZTEXTADDR = 0x00050000 - ZBSSADDR = 0xc0100000 + ZBSSADDR = 0xc0200000 endif ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y) ZTEXTADDR = 0xC0200000 endif +ifeq ($(CONFIG_SA1111),y) + ZRELADDR = 0xc0208000 +endif endif # @@ -105,15 +108,15 @@ export SYSTEM ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS INITRD_VIRT PARAMS_PHYS Image: $(CONFIGURE) $(SYSTEM) - $(OBJCOPY) $(SYSTEM) $@ + $(OBJCOPY) -O binary -R .note -R .comment -S $(SYSTEM) $@ bzImage: zImage zImage: $(CONFIGURE) compressed/vmlinux - $(OBJCOPY) compressed/vmlinux $@ + $(OBJCOPY) -O binary -R .note -R .comment -S compressed/vmlinux $@ bootpImage: bootp/bootp - $(OBJCOPY) bootp/bootp $@ + $(OBJCOPY) -O binary -R .note -R .comment -S bootp/bootp $@ compressed/vmlinux: $(TOPDIR)/vmlinux dep @$(MAKE) -C compressed vmlinux diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/bootp/Makefile linux/arch/arm/boot/bootp/Makefile --- v2.4.1/linux/arch/arm/boot/bootp/Makefile Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/boot/bootp/Makefile Thu Feb 8 16:32:44 2001 @@ -7,7 +7,8 @@ ZLDFLAGS =-p -X -T bootp.lds \ --defsym initrd_addr=$(INITRD_PHYS) \ --defsym initrd_virt=$(INITRD_VIRT) \ - --defsym params=$(PARAMS_PHYS) + --defsym params=$(PARAMS_PHYS) \ + --defsym kernel_addr=$(ZTEXTADDR) all: bootp diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/bootp/init.S linux/arch/arm/boot/bootp/init.S --- v2.4.1/linux/arch/arm/boot/bootp/init.S Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/boot/bootp/init.S Thu Feb 8 16:32:44 2001 @@ -12,33 +12,59 @@ */ .section .start,#alloc,#execinstr .type _entry, #function -_entry: -kernel_addr: adr r10, initdata - ldmia r10, {r11, r12} +_entry: adr r10, initdata + ldr r11, initdata sub r11, r10, r11 @ work out exec offset - add r12, r12, r11 @ correct "splitify" - mov pc, r12 @ jump to splitify + b splitify .size _entry,. - _entry .type initdata, #object initdata: .word initdata @ compiled address of this - .word splitify .size initdata,. - initdata .text splitify: adr r13, data - ldmia r13!, {r4-r6} @ move the kernel + ldmia r13!, {r4-r6} @ move the initrd add r4, r4, r11 @ correction - mov r12, r5 bl move - ldmia r13!, {r4-r6} @ then the initrd + ldmia r13!, {r4-r6} @ then the kernel + mov r12, r5 add r4, r4, r11 @ correction bl move - ldmib r13, {r5,r6,r7} @ get size and addr of initrd - add r7, r7, #16*4 @ offset of initrd_start in param_struct - stmia r7, {r5,r6} @ save in param_struct +/* + * Setup the initrd parameters to pass to the kernel. This can either be + * passed in via a param_struct or a tag list. We spot the param_struct + * method by looking at the first word; this should either indicate a page + * size of 4K, 16K or 32K. + */ + ldmia r13, {r5-r8} @ get size and addr of initrd + @ r5 = ATAG_INITRD + @ r6 = initrd start + @ r7 = initrd end + @ r8 = param_struct address + ldr r9, [r8, #0] @ no param struct? + teq r9, #0x1000 @ 4K? + teqne r9, #0x4000 @ 16K? + teqne r9, #0x8000 @ 32K? + beq no_taglist + +/* + * find the end of the tag list, and then add an INITRD tag on the end. + */ +taglist: ldr r9, [r8, #0] @ tag length + teq r9, #0 @ last tag? + addne r8, r8, r9 + bne taglist + + mov r4, #16 @ length of initrd tag + mov r9, #0 @ end of tag list terminator + stmia r8, {r4, r5, r6, r7, r9} + mov pc, r12 @ call kernel + +no_taglist: add r8, r8, #16*4 + stmia r8, {r6,r7} @ save in param_struct mov pc, r12 @ call kernel move: ldmia r4!, {r7 - r10} @ move 32-bytes at a time @@ -49,17 +75,18 @@ bcs move mov pc, lr -data: .word kernel_start - .word kernel_addr - .word kernel_len - - .word initrd_start +data: .word initrd_start .word initrd_addr .word initrd_len - .word initrd_virt - .word initrd_len - .word params + .word kernel_start + .word kernel_addr + .word kernel_len + + .word 0x54410005 @ r5 = ATAG_INITRD + .word initrd_virt @ r6 + .word initrd_len @ r7 + .word params @ r8 .type kernel_start,#object .type initrd_start,#object diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile --- v2.4.1/linux/arch/arm/boot/compressed/Makefile Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/boot/compressed/Makefile Thu Feb 8 16:32:44 2001 @@ -66,7 +66,7 @@ $(CC) $(AFLAGS) -traditional -c $(HEAD:.o=.S) piggy.o: $(SYSTEM) - $(OBJCOPY) $(SYSTEM) piggy + $(OBJCOPY) -O binary -R .note -R .comment -S $(SYSTEM) piggy gzip $(GZFLAGS) < piggy > piggy.gz $(LD) -r -o $@ -b binary piggy.gz rm -f piggy piggy.gz diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/compressed/head-ftvpci.S linux/arch/arm/boot/compressed/head-ftvpci.S --- v2.4.1/linux/arch/arm/boot/compressed/head-ftvpci.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/boot/compressed/head-ftvpci.S Thu Feb 8 16:32:44 2001 @@ -6,6 +6,13 @@ * Special startup code for FTV PCI board. */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + .section ".start", #alloc, #execinstr ftv_start: mcr p15, 0, r0, c7, c5, 0 @ flush I cache diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/compressed/head-l7200.S linux/arch/arm/boot/compressed/head-l7200.S --- v2.4.1/linux/arch/arm/boot/compressed/head-l7200.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/boot/compressed/head-l7200.S Thu Feb 8 16:32:44 2001 @@ -3,7 +3,7 @@ * * Copyright (C) 2000 Steve Hill * - * Some code borrowed from Nicola Pitre's 'head-sa1100.S' file. This + * Some code borrowed from Nicolas Pitre's 'head-sa1100.S' file. This * is merged with head.S by the linker. */ @@ -16,15 +16,14 @@ .section ".start", #alloc, #execinstr __L7200_start: - mov r0, #0x00100000 @ FLASH address of initrd mov r2, #0xf1000000 @ RAM address of initrd - add r1, r2, #0x00700000 @ Size of initrd + add r3, r2, #0x00700000 @ Size of initrd 1: - ldmia r0!, {r3, r4, r5, r6} - stmia r2!, {r3, r4, r5, r6} - cmp r2, r1 + ldmia r0!, {r4, r5, r6, r7} + stmia r2!, {r4, r5, r6, r7} + cmp r2, r3 ble 1b - + mov r8, #0 @ Zero it out mov r7, #19 @ Set architecture ID diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/compressed/head-sa1100.S linux/arch/arm/boot/compressed/head-sa1100.S --- v2.4.1/linux/arch/arm/boot/compressed/head-sa1100.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/boot/compressed/head-sa1100.S Thu Feb 8 16:32:44 2001 @@ -11,10 +11,6 @@ #include #include -#ifndef CONFIG_ARCH_SA1100 -#error What am I doing here... -#endif - .section ".start", #alloc, #execinstr __SA1100_start: @@ -54,6 +50,8 @@ bic r0, r0, #0x0d @ clear WB, DC, MMU bic r0, r0, #0x1000 @ clear Icache mcr p15, 0, r0, c1, c0, 0 + +#ifdef CONFIG_ANGELBOOT /* * Pause for a short time so that we give enough time * for the host to start a terminal up. @@ -61,3 +59,5 @@ mov r0, #0x00200000 1: subs r0, r0, #1 bne 1b +#endif + diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/compressed/head-shark.S linux/arch/arm/boot/compressed/head-shark.S --- v2.4.1/linux/arch/arm/boot/compressed/head-shark.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/compressed/head-shark.S Thu Feb 8 16:32:44 2001 @@ -0,0 +1,121 @@ +/* The head-file for the Shark + * by Alexander.Schulz@stud.uni-karlsruhe.de + * + * Does the following: + * - get the memory layout from firmware. This can only be done as long as the mmu + * is still on. + * - switch the mmu off, so we have physical addresses + * - copy the kernel to 0x08508000. This is done to have a fixed address where the + * C-parts (misc.c) are executed. This address must be known at compile-time, + * but the load-address of the kernel depends on how much memory is installed. + * - Jump to this location. + * - Set r8 with 0, r7 with the architecture ID for head.S + */ + +#include + +#include + + .section ".start", #alloc, #execinstr + + b __beginning + +__serial_addr: .long 0xf7eff3f8 + .long 0 @ space +__ofw_data: .long 0 @ the number of memory blocks + .space 128 @ (startaddr,size) ... + .space 128 @ bootargs + .align + +__beginning: mov r4, r0 @ save the entry to the firmware + + mov r0, #0xC0 @ disable irq and fiq + mov r1, r0 + mrs r3, cpsr_all + bic r2, r3, r0 + eor r2, r2, r1 + msr cpsr_all, r2 + + ldr r0, __serial_addr @ disable serial interrupt + mov r1, #0 @ hangs the machine, I don t know why. + strb r1, [r0, #0x01] + + mov r0, r4 @ get the Memory layout from firmware + adr r1, __ofw_data + add r2, r1, #4 + mov lr, pc + b SYMBOL_NAME(ofw_init) + mov r1, #0 + + adr r2, __mmu_off @ calculate physical address + sub r2, r2, #0xf0000000 @ openprom maps us at f000 virt, 0e50 phys + adr r0, __ofw_data + ldr r0, [r0, #4] + add r2, r2, r0 + add r2, r2, #0x00500000 + + mrc p15, 0, r3, c1, c0 + bic r3, r3, #0xC @ Write Buffer and DCache + bic r3, r3, #0x1000 @ ICache + mcr p15, 0, r3, c1, c0 @ disabled + + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ flush I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ flush I,D TLBs on v4 + + bic r3, r3, #0x1 @ MMU + mcr p15, 0, r3, c1, c0 @ disabled + + mov pc, r2 + +__copy_target: .long 0x08508000 +__copy_end: .long 0x08608000 + + .word _start + .word __bss_start + + .align +__temp_stack: .space 128 + +__mmu_off: + adr r0, __ofw_data + ldr r0, [r0, #4] + orr r0, r0, #0x00600000 + + ldr r1, __copy_end + ldr r3, __copy_target + +/* r0 = 0x0e600000 (current end of kernelcode) + * r3 = 0x08508000 (where it should begin) + * r1 = 0x08608000 (end of copying area, 1MB) + * The kernel is compressed, so 1 MB should be enough. + * copy the kernel to the beginning of physical memory + * We start from the highest address, so we can copy + * from 0x08500000 to 0x08508000 if we have only 8MB + */ + + +__Copy: ldr r2, [r0], #-4 + str r2, [r1], #-4 + teq r1, r3 + bne __Copy + /* and jump to it */ + adr r2, __go_on + adr r0, __ofw_data + ldr r0, [r0, #4] + sub r2, r2, r0 + sub r2, r2, #0x00500000 + ldr r0, __copy_target + add r2, r2, r0 + mov pc, r2 + +__go_on: + adr sp, __temp_stack + add sp, sp, #128 + adr r0, __ofw_data + mov lr, pc + b SYMBOL_NAME(create_params) + + mov r8, #0 + mov r7, #15 diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S --- v2.4.1/linux/arch/arm/boot/compressed/head.S Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/boot/compressed/head.S Thu Feb 8 16:32:44 2001 @@ -112,8 +112,7 @@ */ .text -1: mrc p15, 0, r6, c0, c0 @ get processor ID - adr r2, LC0 +1: adr r2, LC0 ldmia r2, {r2, r3, r4, r5, sp} mov r0, #0 @@ -124,14 +123,15 @@ cmp r2, r3 blt 1b + mrc p15, 0, r6, c0, c0 @ get processor ID bl cache_on mov r1, sp @ malloc space above stack add r2, sp, #0x10000 @ 64k max teq r4, r5 @ will we overwrite ourselves? - moveq r5, r2 - movne r5, r4 + moveq r5, r2 @ decompress after image + movne r5, r4 @ decompress to final location mov r0, r5 mov r3, r7 diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/compressed/ofw-shark.c linux/arch/arm/boot/compressed/ofw-shark.c --- v2.4.1/linux/arch/arm/boot/compressed/ofw-shark.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/boot/compressed/ofw-shark.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,216 @@ +/* + * linux/arch/arm/boot/compressed/ofw-shark.c + * + * by Alexander.Schulz@stud.uni-karlsruhe.de + * + * This file is used to get some basic information + * about the memory layout of the shark we are running + * on. Memory is usually divided in blocks a 8 MB. + * And bootargs are copied from OpenFirmware. + */ + + +#include +#include +#include + + +asmlinkage void +create_params (unsigned long *buffer) +{ + /* Is there a better address? Also change in kernel/arch.c */ + struct param_struct *params = (struct param_struct *) 0x08003000; + int j,i,m,k,nr_banks,size; + + for (j=0;j<256;j++) params->u1.unused[j]=0; + + size=0; + nr_banks=(unsigned int) buffer[0]; + if (nr_banks > NR_BANKS) nr_banks = NR_BANKS; + for (j=0;ju1.s.pages_in_bank[j]=buffer[2*k+1]|(buffer[2*k+2]/PAGE_SIZE); + size += buffer[2*k+2]; + + buffer[2*k+1]=0xffffffff; /* mark as copied */ + } + + params->u1.s.page_size = PAGE_SIZE; + params->u1.s.nr_pages = size/PAGE_SIZE; + params->u1.s.flags = FLAG_READONLY; + + /* Copy over the bootargs */ + for (j=0;j<128/4;j++) { + ((unsigned long *) params->commandline)[j]=buffer[33+j]; + } +} + + +typedef int (*ofw_handle_t)(void *); + +/* Everything below is called with a wrong MMU setting. + * This means: no string constants, no initialization of + * arrays, no global variables! This is ugly but I didn't + * want to write this in assembler :-) + */ + +int +of_decode_int(const unsigned char *p) +{ + unsigned int i = *p++ << 8; + i = (i + *p++) << 8; + i = (i + *p++) << 8; + return (i + *p); +} + +int +OF_finddevice(ofw_handle_t openfirmware, char *name) +{ + unsigned int args[8]; + char service[12]; + + service[0]='f'; + service[1]='i'; + service[2]='n'; + service[3]='d'; + service[4]='d'; + service[5]='e'; + service[6]='v'; + service[7]='i'; + service[8]='c'; + service[9]='e'; + service[10]='\0'; + + args[0]=(unsigned int)service; + args[1]=1; + args[2]=1; + args[3]=(unsigned int)name; + + if (openfirmware(args) == -1) + return -1; + return args[4]; +} + +int +OF_getproplen(ofw_handle_t openfirmware, int handle, char *prop) +{ + unsigned int args[8]; + char service[12]; + + service[0]='g'; + service[1]='e'; + service[2]='t'; + service[3]='p'; + service[4]='r'; + service[5]='o'; + service[6]='p'; + service[7]='l'; + service[8]='e'; + service[9]='n'; + service[10]='\0'; + + args[0] = (unsigned int)service; + args[1] = 2; + args[2] = 1; + args[3] = (unsigned int)handle; + args[4] = (unsigned int)prop; + + if (openfirmware(args) == -1) + return -1; + return args[5]; +} + +int +OF_getprop(ofw_handle_t openfirmware, int handle, char *prop, void *buf, unsigned int buflen) +{ + unsigned int args[8]; + char service[8]; + + service[0]='g'; + service[1]='e'; + service[2]='t'; + service[3]='p'; + service[4]='r'; + service[5]='o'; + service[6]='p'; + service[7]='\0'; + + args[0] = (unsigned int)service; + args[1] = 4; + args[2] = 1; + args[3] = (unsigned int)handle; + args[4] = (unsigned int)prop; + args[5] = (unsigned int)buf; + args[6] = buflen; + + if (openfirmware(args) == -1) + return -1; + return args[7]; +} + +asmlinkage void ofw_init(ofw_handle_t o, int *nomr, int *pointer) +{ + int phandle,i,mem_len,buffer[32]; + char temp[12]; + + temp[0]='/'; + temp[1]='m'; + temp[2]='e'; + temp[3]='m'; + temp[4]='o'; + temp[5]='r'; + temp[6]='y'; + temp[7]='\0'; + + phandle=OF_finddevice(o,temp); + + temp[0]='r'; + temp[1]='e'; + temp[2]='g'; + temp[3]='\0'; + + mem_len = OF_getproplen(o,phandle, temp); + OF_getprop(o,phandle, temp, buffer, mem_len); + *nomr=mem_len >> 3; + + for (i=0; i<=mem_len/4; i++) pointer[i]=of_decode_int((const unsigned char *)&buffer[i]); + + temp[0]='/'; + temp[1]='c'; + temp[2]='h'; + temp[3]='o'; + temp[4]='s'; + temp[5]='e'; + temp[6]='n'; + temp[7]='\0'; + + phandle=OF_finddevice(o,temp); + + temp[0]='b'; + temp[1]='o'; + temp[2]='o'; + temp[3]='t'; + temp[4]='a'; + temp[5]='r'; + temp[6]='g'; + temp[7]='s'; + temp[8]='\0'; + + mem_len = OF_getproplen(o,phandle, temp); + OF_getprop(o,phandle, temp, buffer, mem_len); + for (i=0; i<=mem_len/4; i++) pointer[i+32]=buffer[i]; + +} diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/compressed/setup-sa1100.S linux/arch/arm/boot/compressed/setup-sa1100.S --- v2.4.1/linux/arch/arm/boot/compressed/setup-sa1100.S Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/boot/compressed/setup-sa1100.S Thu Feb 8 16:32:44 2001 @@ -33,13 +33,11 @@ #define UTSR0 0x1c #define UTSR1 0x20 -#define BAUD_DIV_230400 0x000 -#define BAUD_DIV_115200 0x001 -#define BAUD_DIV_57600 0x003 -#define BAUD_DIV_38400 0x005 -#define BAUD_DIV_19200 0x00b -#define BAUD_DIV_9600 0x017 -#define BAUD_DIV BAUD_DIV_9600 +#ifndef CONFIG_SA1100_DEFAULT_BAUDRATE +#define CONFIG_SA1100_DEFAULT_BAUDRATE 9600 +#endif + +#define BAUD_DIV ((230400/CONFIG_SA1100_DEFAULT_BAUDRATE)-1) SCR_loc: .long SYMBOL_NAME(SCR_value) #define GPIO_2_9 0x3fc @@ -92,7 +90,7 @@ bne skip_uart @ UART3 if Assabet is used with Neponset - teq r3, #25 @ if Assabet + teq r3, #MACH_TYPE_ASSABET @ if Assabet tsteq r2, #(1 << 9) @ ... and Neponset present ldreq r0, UART3_BASE beq uart_init diff -u --recursive --new-file v2.4.1/linux/arch/arm/boot/compressed/vmlinux.lds.in linux/arch/arm/boot/compressed/vmlinux.lds.in --- v2.4.1/linux/arch/arm/boot/compressed/vmlinux.lds.in Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/boot/compressed/vmlinux.lds.in Thu Feb 8 16:32:44 2001 @@ -19,12 +19,13 @@ .text : { _start = .; - head.o(.start) *(.start) - head.o(.text) *(.text) *(.fixup) *(.gnu.warning) + *(.rodata) + *(.glue_7) + *(.glue_7t) input_data = .; piggy.o input_data_end = .; diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile --- v2.4.1/linux/arch/arm/kernel/Makefile Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/kernel/Makefile Thu Feb 8 16:32:44 2001 @@ -10,16 +10,14 @@ HEAD_OBJ = head-$(PROCESSOR).o ENTRY_OBJ = entry-$(PROCESSOR).o -AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional -AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional +AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) +AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) O_OBJS_arc = dma-arc.o oldlatches.o O_OBJS_rpc = dma-rpc.o O_OBJS_footbridge = dma-footbridge.o isa.o O_OBJS_l7200 = fiq.o -leds-ebsa110 = leds-ebsa110.o - pci-nexuspci = plx90x0.o pci-footbridge = dec21285.o pci-shark = via82c505.o @@ -31,36 +29,28 @@ # Object file lists. -obj-y := arch.o dma.o $(ENTRY_OBJ) irq.o process.o ptrace.o \ - semaphore.o setup.o signal.o sys_arm.o time.o \ - traps.o $(O_OBJS_$(MACHINE)) -obj-m := -obj-n := -obj- := - -export-objs := armksyms.o dma.o ecard.o \ - $(leds-$(MACHINE)) oldlatches.o \ - time.o +obj-y := arch.o dma.o $(ENTRY_OBJ) irq.o process.o ptrace.o \ + semaphore.o setup.o signal.o sys_arm.o time.o traps.o \ + $(O_OBJS_$(MACHINE)) +obj-m := +obj-n := +obj- := + +export-objs := armksyms.o dma.o ecard.o fiq.o oldlatches.o time.o + +no-irq-arch := $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \ + $(CONFIG_ARCH_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) + +ifneq ($(findstring y,$(no-irq-arch)),y) + obj-y += irq-arch.o +endif obj-$(CONFIG_ARCH_ACORN) += ecard.o fiq.o time-acorn.o obj-$(CONFIG_DEBUG_LL) += debug-$(PROCESSOR).o obj-$(CONFIG_MODULES) += armksyms.o -obj-$(CONFIG_LEDS) += $(leds-$(MACHINE)) obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o - obj-$(CONFIG_PCI) += bios32.o $(pci-$(MACHINE)) $(pci-y) - -# Files that are both resident and modular; remove from modular. - -obj-m := $(filter-out $(obj-y), $(obj-m)) - -# Translate to Rules.make lists. - -O_OBJS := $(filter-out $(export-objs), $(obj-y)) -OX_OBJS := $(filter $(export-objs), $(obj-y)) -M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) all: kernel.o $(HEAD_OBJ) init_task.o diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.4.1/linux/arch/arm/kernel/bios32.c Mon Nov 27 17:51:34 2000 +++ linux/arch/arm/kernel/bios32.c Thu Feb 8 16:32:44 2001 @@ -257,11 +257,30 @@ (struct arm_pci_sysdata *)bus->sysdata; struct arm_bus_sysdata *busdata; - if (bus->number < MAX_NR_BUS) - busdata = sysdata->bus + bus->number; - else + if (bus->number >= MAX_NR_BUS) BUG(); + if (bus->self) { + struct pci_dev *dev = bus->self; + int i; + + for (i = 0; i < 3; i++) { + bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES + i]; + bus->resource[i]->name = bus->name; + } + bus->resource[0]->start = ioport_resource.start; + bus->resource[0]->end = ioport_resource.end; + bus->resource[0]->flags |= pci_bridge_check_io(dev); + bus->resource[1]->start = iomem_resource.start; + bus->resource[1]->end = iomem_resource.end; + bus->resource[1]->flags |= IORESOURCE_MEM; + + /* Turn off downsteam prefetchable memory address range */ + bus->resource[2]->start = 1024*1024; + bus->resource[2]->end = bus->resource[2]->start - 1; + } + + busdata = sysdata->bus + bus->number; busdata->max_lat = 255; /* @@ -363,10 +382,6 @@ 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; } u8 __init no_swizzle(struct pci_dev *dev, u8 *pin) @@ -442,7 +457,8 @@ hw_pci->init(&sysdata); /* - * Other architectures don't seem to do this... should we? + * Claim the currently allocated resources. This ensures + * that we will not allocate an already inuse region. */ pcibios_claim_resources(); diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/dma-arc.c linux/arch/arm/kernel/dma-arc.c --- v2.4.1/linux/arch/arm/kernel/dma-arc.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/kernel/dma-arc.c Thu Feb 8 16:32:44 2001 @@ -40,7 +40,7 @@ memcpy ((void *)0x1c, (void *)&fdc1772_dma_read, &fdc1772_dma_read_end - &fdc1772_dma_read); fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */ - enable_irq (64); + enable_fiq(FIQ_FLOPPYDATA); restore_flags(flags); } break; @@ -55,7 +55,7 @@ memcpy ((void *)0x1c, (void *)&fdc1772_dma_write, &fdc1772_dma_write_end - &fdc1772_dma_write); fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */ - enable_irq (64); + enable_fiq(FIQ_FLOPPYDATA; restore_flags(flags); } @@ -102,7 +102,7 @@ static void arc_disable_dma(dmach_t channel, dma_t *dma) { - disable_irq(dma->dma_irq); + disable_fiq(dma->dma_irq); } static struct dma_ops arc_floppy_data_dma_ops = { @@ -158,12 +158,12 @@ regs.ARM_r10 = dma->buf.address; regs.ARM_fp = FLOPPYDMA_BASE; set_fiq_regs(®s); - enable_irq(dma->dma_irq); + enable_fiq(dma->dma_irq); } static void a5k_floppy_disable_dma(dmach_t channel, dma_t *dma) { - disable_irq(dma->dma_irq); + disable_fiq(dma->dma_irq); release_fiq(&fh); } @@ -192,15 +192,15 @@ { #if defined(CONFIG_BLK_DEV_FD1772) || defined(CONFIG_BLK_DEV_FD1772_MODULE) if (machine_is_archimedes()) { - dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64; + dma[DMA_VIRTUAL_FLOPPY0].dma_irq = FIQ_FLOPPYDATA; dma[DMA_VIRTUAL_FLOPPY0].d_ops = &arc_floppy_data_dma_ops; - dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 65; + dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 1; dma[DMA_VIRTUAL_FLOPPY1].d_ops = &arc_floppy_cmdend_dma_ops; } #endif #ifdef CONFIG_ARCH_A5K if (machine_is_a5k()) { - dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64; + dma[DMA_VIRTUAL_FLOPPY0].dma_irq = FIQ_FLOPPYDATA; dma[DMA_VIRTUAL_FLOPPY0].d_ops = &a5k_floppy_dma_ops; } #endif diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c --- v2.4.1/linux/arch/arm/kernel/dma-rpc.c Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/kernel/dma-rpc.c Fri Feb 9 11:29:44 2001 @@ -10,7 +10,7 @@ * DMA functions specific to RiscPC architecture */ #include -#include +#include #include #include #include @@ -42,11 +42,11 @@ #define TRANSFER_SIZE 2 #define CURA (0) -#define ENDA ((IOMD_IO0ENDA - IOMD_IO0CURA) << 2) -#define CURB ((IOMD_IO0CURB - IOMD_IO0CURA) << 2) -#define ENDB ((IOMD_IO0ENDB - IOMD_IO0CURA) << 2) -#define CR ((IOMD_IO0CR - IOMD_IO0CURA) << 2) -#define ST ((IOMD_IO0ST - IOMD_IO0CURA) << 2) +#define ENDA (IOMD_IO0ENDA - IOMD_IO0CURA) +#define CURB (IOMD_IO0CURB - IOMD_IO0CURA) +#define ENDB (IOMD_IO0ENDB - IOMD_IO0CURA) +#define CR (IOMD_IO0CR - IOMD_IO0CURA) +#define ST (IOMD_IO0ST - IOMD_IO0CURA) #define state_prog_a 0 #define state_wait_a 1 @@ -93,14 +93,14 @@ static inline void iomd_setup_dma_a(struct scatterlist *sg, dma_t *dma) { - outl_t(sg->dma_address, dma->dma_base + CURA); - outl_t(sg->length, dma->dma_base + ENDA); + iomd_writel(sg->dma_address, dma->dma_base + CURA); + iomd_writel(sg->length, dma->dma_base + ENDA); } static inline void iomd_setup_dma_b(struct scatterlist *sg, dma_t *dma) { - outl_t(sg->dma_address, dma->dma_base + CURB); - outl_t(sg->length, dma->dma_base + ENDB); + iomd_writel(sg->dma_address, dma->dma_base + CURB); + iomd_writel(sg->length, dma->dma_base + ENDB); } static void iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs) @@ -116,7 +116,7 @@ dma->state = state_wait_a; case state_wait_a: - status = inb_t(dma->dma_base + ST); + status = iomd_readb(dma->dma_base + ST); switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) { case DMA_ST_OFL|DMA_ST_INT: iomd_get_next_sg(&dma->cur_sg, dma); @@ -137,7 +137,7 @@ break; case state_wait_b: - status = inb_t(dma->dma_base + ST); + status = iomd_readb(dma->dma_base + ST); switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) { case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB: iomd_get_next_sg(&dma->cur_sg, dma); @@ -193,14 +193,14 @@ PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); } - outb_t(DMA_CR_C, dma_base + CR); + iomd_writeb(DMA_CR_C, dma_base + CR); dma->state = state_prog_a; } if (dma->dma_mode == DMA_MODE_READ) ctrl |= DMA_CR_D; - outb_t(ctrl, dma_base + CR); + iomd_writeb(ctrl, dma_base + CR); enable_irq(dma->dma_irq); } @@ -210,8 +210,8 @@ unsigned int ctrl; disable_irq(dma->dma_irq); - ctrl = inb_t(dma_base + CR); - outb_t(ctrl & ~DMA_CR_E, dma_base + CR); + ctrl = iomd_readb(dma_base + CR); + iomd_writeb(ctrl & ~DMA_CR_E, dma_base + CR); } static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle) @@ -227,7 +227,7 @@ else speed = 0; - tcr = inb(IOMD_DMATCR); + tcr = iomd_readb(IOMD_DMATCR); speed &= 3; switch (channel) { @@ -251,7 +251,7 @@ break; } - outb(tcr, IOMD_DMATCR); + iomd_writeb(tcr, IOMD_DMATCR); return speed; } @@ -287,7 +287,7 @@ regs.ARM_r9 = dma->buf.length; regs.ARM_r10 = (unsigned long)dma->buf.address; - regs.ARM_fp = (unsigned long)PCIO_FLOPPYDMABASE; + regs.ARM_fp = FLOPPYDMA_BASE; if (claim_fiq(&fh)) { printk("floppydma: couldn't claim FIQ.\n"); @@ -296,12 +296,12 @@ set_fiq_handler(fiqhandler_start, fiqhandler_length); set_fiq_regs(®s); - enable_irq(dma->dma_irq); + enable_fiq(dma->dma_irq); } static void floppy_disable_dma(dmach_t channel, dma_t *dma) { - disable_irq(dma->dma_irq); + disable_fiq(dma->dma_irq); release_fiq(&fh); } @@ -334,32 +334,32 @@ void __init arch_dma_init(dma_t *dma) { - outb(0, IOMD_IO0CR); - outb(0, IOMD_IO1CR); - outb(0, IOMD_IO2CR); - outb(0, IOMD_IO3CR); + iomd_writeb(0, IOMD_IO0CR); + iomd_writeb(0, IOMD_IO1CR); + iomd_writeb(0, IOMD_IO2CR); + iomd_writeb(0, IOMD_IO3CR); - outb(0xa0, IOMD_DMATCR); + iomd_writeb(0xa0, IOMD_DMATCR); - dma[DMA_0].dma_base = ioaddr(IOMD_IO0CURA); + dma[DMA_0].dma_base = IOMD_IO0CURA; dma[DMA_0].dma_irq = IRQ_DMA0; dma[DMA_0].d_ops = &iomd_dma_ops; - dma[DMA_1].dma_base = ioaddr(IOMD_IO1CURA); + dma[DMA_1].dma_base = IOMD_IO1CURA; dma[DMA_1].dma_irq = IRQ_DMA1; dma[DMA_1].d_ops = &iomd_dma_ops; - dma[DMA_2].dma_base = ioaddr(IOMD_IO2CURA); + dma[DMA_2].dma_base = IOMD_IO2CURA; dma[DMA_2].dma_irq = IRQ_DMA2; dma[DMA_2].d_ops = &iomd_dma_ops; - dma[DMA_3].dma_base = ioaddr(IOMD_IO3CURA); + dma[DMA_3].dma_base = IOMD_IO3CURA; dma[DMA_3].dma_irq = IRQ_DMA3; dma[DMA_3].d_ops = &iomd_dma_ops; - dma[DMA_S0].dma_base = ioaddr(IOMD_SD0CURA); + dma[DMA_S0].dma_base = IOMD_SD0CURA; dma[DMA_S0].dma_irq = IRQ_DMAS0; dma[DMA_S0].d_ops = &iomd_dma_ops; - dma[DMA_S1].dma_base = ioaddr(IOMD_SD1CURA); + dma[DMA_S1].dma_base = IOMD_SD1CURA; dma[DMA_S1].dma_irq = IRQ_DMAS1; dma[DMA_S1].d_ops = &iomd_dma_ops; - dma[DMA_VIRTUAL_FLOPPY].dma_irq = 64; + dma[DMA_VIRTUAL_FLOPPY].dma_irq = FIQ_FLOPPYDATA; dma[DMA_VIRTUAL_FLOPPY].d_ops = &floppy_dma_ops; dma[DMA_VIRTUAL_SOUND].d_ops = &sound_dma_ops; @@ -367,5 +367,5 @@ * Setup DMA channels 2,3 to be for podules * and channels 0,1 for internal devices */ - outb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT); + iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT); } diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/dma.c linux/arch/arm/kernel/dma.c --- v2.4.1/linux/arch/arm/kernel/dma.c Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/kernel/dma.c Fri Feb 9 11:29:44 2001 @@ -12,7 +12,7 @@ * DMA facilities. */ #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c --- v2.4.1/linux/arch/arm/kernel/ecard.c Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/kernel/ecard.c Fri Feb 9 11:29:44 2001 @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/entry-armo.S linux/arch/arm/kernel/entry-armo.S --- v2.4.1/linux/arch/arm/kernel/entry-armo.S Mon Sep 18 15:15:24 2000 +++ linux/arch/arm/kernel/entry-armo.S Thu Feb 8 16:32:44 2001 @@ -197,8 +197,7 @@ #endif #define FAULT_CODE_PREFETCH 0x04 #define FAULT_CODE_WRITE 0x02 -#define FAULT_CODE_USER 0x01 - +#define FAULT_CODE_FORCECOW 0x01 #define SVC_SAVE_ALL \ str sp, [sp, #-16]! ;\ @@ -487,7 +486,6 @@ save_user_regs teqp pc, #0x00000003 @ NOT a problem - doesnt change mode mask_pc r0, lr - mov r2, #FAULT_CODE_USER bl Ldata_do b ret_from_exception @@ -499,7 +497,6 @@ tst lr, #0x08000000 teqeqp pc, #0x00000003 @ NOT a problem - doesnt change mode mask_pc r0, lr - mov r2, #0 bl Ldata_do SVC_RESTORE_ALL @@ -510,6 +507,7 @@ Ldata_do: mov r3, sp ldr r4, [r0] @ Get instruction + mov r2, #0 tst r4, #1 << 20 @ Check to see if it is a write instruction orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction mov r1, r4, lsr #22 @ Now branch to the relevent processing routine diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/fiq.c linux/arch/arm/kernel/fiq.c --- v2.4.1/linux/arch/arm/kernel/fiq.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/kernel/fiq.c Thu Feb 8 16:32:44 2001 @@ -36,12 +36,14 @@ * 6. Goto 3 */ #include +#include #include #include #include #include #include +#include #include #include #include @@ -71,7 +73,7 @@ * - we always relinquish FIQ control * - we always reacquire FIQ control */ -int fiq_def_op(void *ref, int relinquish) +static int fiq_def_op(void *ref, int relinquish) { if (!relinquish) { unprotect_page_0(); @@ -213,6 +215,24 @@ current_fiq = current_fiq->next; while (current_fiq->fiq_op(current_fiq->dev_id, 0)); } + +void enable_fiq(int fiq) +{ + enable_irq(fiq + FIQ_START); +} + +void disable_fiq(int fiq) +{ + disable_irq(fiq + FIQ_START); +} + +EXPORT_SYMBOL(set_fiq_handler); +EXPORT_SYMBOL(set_fiq_regs); +EXPORT_SYMBOL(get_fiq_regs); +EXPORT_SYMBOL(claim_fiq); +EXPORT_SYMBOL(release_fiq); +EXPORT_SYMBOL(enable_fiq); +EXPORT_SYMBOL(disable_fiq); void __init init_FIQ(void) { diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.4.1/linux/arch/arm/kernel/irq.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/kernel/irq.c Fri Feb 9 11:29:44 2001 @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.4.1/linux/arch/arm/kernel/process.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/kernel/process.c Fri Feb 9 11:29:44 2001 @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -92,8 +92,10 @@ void (*idle)(void) = pm_idle; if (!idle) idle = arch_idle; + leds_event(led_idle_start); while (!current->need_resched) idle(); + leds_event(led_idle_end); schedule(); #ifndef CONFIG_NO_PGT_CACHE check_pgt_cache(); @@ -364,20 +366,23 @@ */ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { - extern long sys_exit(int) __attribute__((noreturn)); pid_t __ret; __asm__ __volatile__( - "mov r0, %1 @ kernel_thread sys_clone + "orr r0, %1, %2 @ kernel_thread sys_clone mov r1, #0 "__syscall(clone)" - teq r0, #0 @ if we are the child - moveq fp, #0 @ ensure that fp is zero - mov %0, r0" + movs %0, r0 @ if we are the child + bne 1f + mov fp, #0 @ ensure that fp is zero + mov r0, %4 + mov lr, pc + mov pc, %3 + b sys_exit +1: " : "=r" (__ret) - : "Ir" (flags | CLONE_VM) : "r0", "r1"); - if (__ret == 0) - sys_exit((fn)(arg)); + : "Ir" (flags), "I" (CLONE_VM), "r" (fn), "r" (arg) + : "r0", "r1", "lr"); return __ret; } diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c --- v2.4.1/linux/arch/arm/kernel/sys_arm.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/kernel/sys_arm.c Fri Feb 9 11:29:44 2001 @@ -14,7 +14,7 @@ */ #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c --- v2.4.1/linux/arch/arm/kernel/time.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/kernel/time.c Thu Feb 8 16:32:44 2001 @@ -134,32 +134,17 @@ #ifdef CONFIG_MODULES EXPORT_SYMBOL(leds_event); #endif +#endif +#ifdef CONFIG_LEDS_TIMER static void do_leds(void) { -#ifdef CONFIG_LEDS_CPU - { - static int last_pid; + static unsigned int count = 50; - if (current->pid != last_pid) { - last_pid = current->pid; - if (last_pid) - leds_event(led_idle_end); - else - leds_event(led_idle_start); - } + if (--count == 0) { + count = 50; + leds_event(led_timer); } -#endif -#ifdef CONFIG_LEDS_TIMER - { - static unsigned int count = 50; - - if (--count == 0) { - count = 50; - leds_event(led_timer); - } - } -#endif } #else #define do_leds() diff -u --recursive --new-file v2.4.1/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c --- v2.4.1/linux/arch/arm/kernel/traps.c Sun Dec 3 17:48:19 2000 +++ linux/arch/arm/kernel/traps.c Thu Feb 8 16:32:44 2001 @@ -107,7 +107,7 @@ bad = __get_user(val, &((u32 *)addr)[i]); if (!bad) - printk(i == 0 ? "(%0*x) " : "%0*x", width, val); + printk(i == 0 ? "(%0*x) " : "%0*x ", width, val); else { printk("bad PC value."); break; @@ -133,7 +133,7 @@ printk("no frame pointer"); ok = 0; } else if (verify_stack(fp)) { - printk("invalid frame pointer %08lx", fp); + printk("invalid frame pointer 0x%08x", fp); ok = 0; } else if (fp < 4096+(unsigned long)tsk) printk("frame pointer underflow"); diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.4.1/linux/arch/arm/lib/Makefile Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/Makefile Thu Feb 8 16:32:44 2001 @@ -1,57 +1,57 @@ # # linux/arch/arm/lib/Makefile # -# Copyright (C) 1995-1999 Russell King +# Copyright (C) 1995-2000 Russell King # USE_STANDARD_AS_RULE := true -L_TARGET := lib.a -L_OBJS := changebit.o csumipv6.o csumpartial.o csumpartialcopy.o \ - csumpartialcopyuser.o clearbit.o copy_page.o findbit.o \ - memchr.o memcpy.o memset.o memzero.o setbit.o \ - strncpy_from_user.o strnlen_user.o strchr.o strrchr.o \ - testchangebit.o testclearbit.o testsetbit.o uaccess.o - -l-obj-y := -l-obj-n := - -O_TARGET := lib.o -O_OBJS := backtrace.o delay.o - -ifeq ($(CONFIG_ARCH_ACORN),y) - half := n - full := y +L_TARGET := lib.a + +obj-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ + csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ + copy_page.o delay.o findbit.o memchr.o memcpy.o \ + memset.o memzero.o setbit.o strncpy_from_user.o \ + strnlen_user.o strchr.o strrchr.o testchangebit.o \ + testclearbit.o testsetbit.o uaccess.o +obj-m := +obj-n := + +export-objs := io.o + +obj-arc := ecard.o io-acorn.o floppydma.o +obj-rpc := ecard.o io-acorn.o floppydma.o +obj-clps7500 := io-acorn.o +obj-footbridge := io-pcio.o +obj-l7200 := io-acorn.o +obj-nexuspci := io-pcio.o +obj-sa1100 := io-pcio.o +obj-shark := io-shark.o +obj-integrator := io-pcio.o +obj-clps711x := io-shark.o + +obj-y += $(obj-$(MACHINE)) + +ifeq ($(CONFIG_CPU_32v4),y) + v3 := n + v4 := y else - half := y - full := n + v3 := y + v4 := n endif -L_OBJS_arc := ecard.o io-acorn.o floppydma.o -L_OBJS_rpc := ecard.o io-acorn.o floppydma.o -L_OBJS_clps7500 := io-acorn.o -L_OBJS_footbridge := io-pcio.o -L_OBJS_l7200 := io-acorn.o -L_OBJS_nexuspci := io-pcio.o -L_OBJS_sa1100 := io-pcio.o -L_OBJS_shark := io-shark.o -L_OBJS_integrator := io-pcio.o -L_OBJS_clps711x := io-shark.o - -l-obj-y += io-readsb.o io-writesb.o -l-obj-$(full) += io-readsw-armv3.o io-writesw-armv3.o -l-obj-$(half) += io-readsw-armv4.o io-writesw-armv4.o -l-obj-y += io-readsl.o io-writesl.o +obj-y += io-readsb.o io-writesb.o +obj-$(v3) += io-readsw-armv3.o io-writesw-armv3.o io-readsl-armv3.o +obj-$(v4) += io-readsw-armv4.o io-writesw-armv4.o io-readsl-armv4.o +obj-y += io-writesl.o ifeq ($(PROCESSOR),armo) - L_OBJS += uaccess-armo.o + obj-y += uaccess-armo.o endif ifneq ($(MACHINE),ebsa110) - OX_OBJS += io.o + obj-y += io.o endif - -L_OBJS += $(L_OBJS_$(MACHINE)) $(l-obj-y) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-acorn.S linux/arch/arm/lib/io-acorn.S --- v2.4.1/linux/arch/arm/lib/io-acorn.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/io-acorn.S Thu Feb 8 16:32:44 2001 @@ -60,32 +60,32 @@ */ ENTRY(insw) - teq r2, #0 - RETINSTR(moveq, pc, lr) addr r0 - b __arch_readsw + teq r2, #0 + bne __arch_readsw + RETINSTR(mov, pc, lr) ENTRY(insb) - teq r2, #0 - RETINSTR(moveq, pc, lr) addr r0 - b __arch_readsb + teq r2, #0 + bne __arch_readsb + RETINSTR(mov, pc, lr) @ Purpose: write a block of data from memory to a hardware register. @ Proto : outsw(int to_reg, void *from, int len_in_words); @ Notes : increments from ENTRY(outsw) - teq r2, #0 - RETINSTR(moveq, pc, lr) addr r0 - b __arch_writesw + teq r2, #0 + bne __arch_writesw + RETINSTR(mov, pc, lr) ENTRY(outsb) - teq r2, #0 - RETINSTR(moveq, pc, lr) addr r0 - b __arch_writesb + teq r2, #0 + bne __arch_writesb + RETINSTR(mov, pc, lr) @ Purpose: write a memc register @ Proto : void memc_write(int register, int value); diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-pcio.S linux/arch/arm/lib/io-pcio.S --- v2.4.1/linux/arch/arm/lib/io-pcio.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/io-pcio.S Thu Feb 8 16:32:44 2001 @@ -1,4 +1,5 @@ #include +#include #include .equ pcio_high, PCIO_BASE & 0xff000000 @@ -13,26 +14,37 @@ ENTRY(insl) ioaddr r0, r0 - b __arch_readsl + teq r2, #0 + bne __arch_readsl + RETINSTR(mov, pc, lr) ENTRY(outsl) ioaddr r0, r0 - b __arch_writesl - - /* Nobody could say these are optimal, but not to worry. */ + teq r2, #0 + bne __arch_writesl + RETINSTR(mov, pc, lr) ENTRY(outsw) ioaddr r0, r0 - b __arch_writesw + teq r2, #0 + bne __arch_writesw + RETINSTR(mov, pc, lr) ENTRY(insw) ioaddr r0, r0 - b __arch_readsw + teq r2, #0 + bne __arch_readsw + RETINSTR(mov, pc, lr) ENTRY(insb) ioaddr r0, r0 - b __arch_readsb + teq r2, #0 + bne __arch_readsb + RETINSTR(mov, pc, lr) ENTRY(outsb) ioaddr r0, r0 - b __arch_writesb + teq r2, #0 + bne __arch_writesb + RETINSTR(mov, pc, lr) + diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-readsb.S linux/arch/arm/lib/io-readsb.S --- v2.4.1/linux/arch/arm/lib/io-readsb.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/io-readsb.S Thu Feb 8 16:32:44 2001 @@ -62,6 +62,7 @@ ldrb ip, [r0] orr r6, r6, ip, lsl #24 stmia r1!, {r3 - r6} + subs r2, r2, #16 bpl .insb_16_lp @@ -88,7 +89,7 @@ stmia r1!, {r3, r4} .insb_no_8: tst r2, #4 - bne .insb_no_4 + beq .insb_no_4 ldrb r3, [r0] ldrb r4, [r0] @@ -101,6 +102,7 @@ .insb_no_4: ands r2, r2, #3 LOADREGS(eqfd, sp!, {r4 - r6, pc}) + cmp r2, #2 ldrb r3, [r0] strb r3, [r1], #1 @@ -108,4 +110,5 @@ strgeb r3, [r1], #1 ldrgtb r3, [r0] strgtb r3, [r1] + LOADREGS(fd, sp!, {r4 - r6, pc}) diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-readsl-armv3.S linux/arch/arm/lib/io-readsl-armv3.S --- v2.4.1/linux/arch/arm/lib/io-readsl-armv3.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/lib/io-readsl-armv3.S Thu Feb 8 16:32:44 2001 @@ -0,0 +1,76 @@ +/* + * linux/arch/arm/lib/io-readsl-armv3.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +/* + * Note that some reads can be aligned on half-word boundaries. + */ +ENTRY(__arch_readsl) + ands ip, r1, #3 + bne 2f + +1: ldr r3, [r0] + str r3, [r1], #4 + subs r2, r2, #1 + bne 1b + mov pc, lr + +2: cmp ip, #2 + ldr ip, [r0] + blt 4f + bgt 6f + + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov ip, ip, lsr #8 +3: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #16 + strne ip, [r1], #4 + movne ip, r3, lsr #16 + bne 3b + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov pc, lr + +4: strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov ip, ip, lsr #8 +5: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #8 + strne ip, [r1], #4 + movne ip, r3, lsr #24 + bne 5b + strb ip, [r1], #1 + mov pc, lr + +6: strb ip, [r1], #1 + mov ip, ip, lsr #8 +7: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #24 + strne ip, [r1], #4 + movne ip, r3, lsr #8 + bne 7b + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov pc, lr + diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-readsl-armv4.S linux/arch/arm/lib/io-readsl-armv4.S --- v2.4.1/linux/arch/arm/lib/io-readsl-armv4.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/lib/io-readsl-armv4.S Thu Feb 8 16:32:44 2001 @@ -0,0 +1,68 @@ +/* + * linux/arch/arm/lib/io-readsl-armv4.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +/* + * Note that some reads can be aligned on half-word boundaries. + */ +ENTRY(__arch_readsl) + ands ip, r1, #3 + bne 2f + +1: ldr r3, [r0] + str r3, [r1], #4 + subs r2, r2, #1 + bne 1b + mov pc, lr + +2: cmp ip, #2 + ldr ip, [r0] + blt 4f + bgt 6f + + strh ip, [r1], #2 + mov ip, ip, lsr #16 +3: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #16 + strne ip, [r1], #4 + movne ip, r3, lsr #16 + bne 3b + strh ip, [r1], #2 + mov pc, lr + +4: strb ip, [r1], #1 + mov ip, ip, lsr #8 + strh ip, [r1], #2 + mov ip, ip, lsr #16 +5: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #8 + strne ip, [r1], #4 + movne ip, r3, lsr #24 + bne 5b + strb ip, [r1], #1 + mov pc, lr + +6: strb ip, [r1], #1 + mov ip, ip, lsr #8 +7: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #24 + strne ip, [r1], #4 + movne ip, r3, lsr #8 + bne 7b + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strh ip, [r1], #2 + mov pc, lr + diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-readsl.S linux/arch/arm/lib/io-readsl.S --- v2.4.1/linux/arch/arm/lib/io-readsl.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/io-readsl.S Wed Dec 31 16:00:00 1969 @@ -1,65 +0,0 @@ -/* - * linux/arch/arm/lib/io-readsb.S - * - * Copyright (C) 1995-2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include - -ENTRY(__arch_readsl) - ands ip, r1, #3 - bne 2f - -1: ldr r3, [r0] - str r3, [r1], #4 - subs r2, r2, #1 - bne 1b - mov pc, lr - -2: cmp ip, #2 - ldr ip, [r0] - blt 4f - bgt 6f - - strh ip, [r1], #2 - mov ip, ip, lsr #16 -3: subs r2, r2, #1 - ldrne r3, [r0] - orrne ip, ip, r3, lsl #16 - strne ip, [r1], #4 - movne ip, r3, lsr #16 - bne 3b - strh ip, [r1], #2 - mov pc, lr - -4: strb ip, [r1], #1 - mov ip, ip, lsr #8 - strh ip, [r1], #2 - mov ip, ip, lsr #16 -5: subs r2, r2, #1 - ldrne r3, [r0] - orrne ip, ip, r3, lsl #8 - strne ip, [r1], #4 - movne ip, r3, lsr #24 - bne 5b - strb ip, [r1], #1 - mov pc, lr - -6: strb ip, [r1], #1 - mov ip, ip, lsr #8 -7: subs r2, r2, #1 - ldrne r3, [r0] - orrne ip, ip, r3, lsl #24 - strne ip, [r1], #4 - movne ip, r3, lsr #8 - bne 7b - strb ip, [r1], #1 - mov ip, ip, lsr #8 - strh ip, [r1], #2 - mov pc, lr - diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-readsw-armv3.S linux/arch/arm/lib/io-readsw-armv3.S --- v2.4.1/linux/arch/arm/lib/io-readsw-armv3.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/io-readsw-armv3.S Thu Feb 8 16:32:44 2001 @@ -1,5 +1,5 @@ /* - * linux/arch/arm/lib/io-readsb.S + * linux/arch/arm/lib/io-readsw-armv3.S * * Copyright (C) 1995-2000 Russell King * @@ -62,8 +62,10 @@ orr r6, r6, lr, lsl #16 stmia r1!, {r3 - r6} + subs r2, r2, #8 bpl .insw_8_lp + tst r2, #7 LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) @@ -97,6 +99,7 @@ strneb r3, [r1], #1 movne r3, r3, lsr #8 strneb r3, [r1] + LOADREGS(fd, sp!, {r4, r5, r6, pc}) diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-readsw-armv4.S linux/arch/arm/lib/io-readsw-armv4.S --- v2.4.1/linux/arch/arm/lib/io-readsw-armv4.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/io-readsw-armv4.S Thu Feb 8 16:32:44 2001 @@ -1,5 +1,5 @@ /* - * linux/arch/arm/lib/io-readsb.S + * linux/arch/arm/lib/io-readsw-armv4.S * * Copyright (C) 1995-2000 Russell King * @@ -46,16 +46,18 @@ orr r4, r4, r5, lsl #16 ldrh r5, [r0] - ldrh r6, [r0] - orr r5, r5, r6, lsl #16 + ldrh ip, [r0] + orr r5, r5, ip, lsl #16 ldrh ip, [r0] ldrh lr, [r0] orr ip, ip, lr, lsl #16 stmia r1!, {r3 - r5, ip} + subs r2, r2, #8 bpl .insw_8_lp + tst r2, #7 LOADREGS(eqfd, sp!, {r4, r5, pc}) @@ -84,4 +86,5 @@ .no_insw_2: tst r2, #1 ldrneh r3, [r0] strneh r3, [r1] + LOADREGS(fd, sp!, {r4, r5, pc}) diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-writesb.S linux/arch/arm/lib/io-writesb.S --- v2.4.1/linux/arch/arm/lib/io-writesb.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/io-writesb.S Thu Feb 8 16:32:44 2001 @@ -1,5 +1,5 @@ /* - * linux/arch/arm/lib/io-readsb.S + * linux/arch/arm/lib/io-writesb.S * * Copyright (C) 1995-2000 Russell King * @@ -13,7 +13,7 @@ .outsb_align: rsb ip, ip, #4 cmp ip, r2 - mov ip, r2 + movgt ip, r2 cmp ip, #2 ldrb r3, [r1], #1 strb r3, [r0] @@ -34,6 +34,7 @@ bmi .outsb_no_16 .outsb_16_lp: ldmia r1!, {r3 - r6} + strb r3, [r0] mov r3, r3, lsr #8 strb r3, [r0] @@ -65,6 +66,7 @@ strb r6, [r0] mov r6, r6, lsr #8 strb r6, [r0] + subs r2, r2, #16 bpl .outsb_16_lp @@ -74,7 +76,8 @@ .outsb_no_16: tst r2, #8 beq .outsb_no_8 - ldmia r1, {r3, r4} + ldmia r1!, {r3, r4} + strb r3, [r0] mov r3, r3, lsr #8 strb r3, [r0] @@ -92,7 +95,7 @@ strb r4, [r0] .outsb_no_8: tst r2, #4 - bne .outsb_no_4 + beq .outsb_no_4 ldr r3, [r1], #4 strb r3, [r0] @@ -105,6 +108,7 @@ .outsb_no_4: ands r2, r2, #3 LOADREGS(eqfd, sp!, {r4 - r6, pc}) + cmp r2, #2 ldrb r3, [r1], #1 strb r3, [r0] @@ -112,4 +116,5 @@ strgeb r3, [r0] ldrgtb r3, [r1] strgtb r3, [r0] + LOADREGS(fd, sp!, {r4 - r6, pc}) diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-writesl.S linux/arch/arm/lib/io-writesl.S --- v2.4.1/linux/arch/arm/lib/io-writesl.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/io-writesl.S Thu Feb 8 16:32:44 2001 @@ -1,5 +1,5 @@ /* - * linux/arch/arm/lib/io-readsb.S + * linux/arch/arm/lib/io-writesl.S * * Copyright (C) 1995-2000 Russell King * diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-writesw-armv3.S linux/arch/arm/lib/io-writesw-armv3.S --- v2.4.1/linux/arch/arm/lib/io-writesw-armv3.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/io-writesw-armv3.S Thu Feb 8 16:32:44 2001 @@ -1,5 +1,5 @@ /* - * linux/arch/arm/lib/io-readsb.S + * linux/arch/arm/lib/io-writesw-armv3.S * * Copyright (C) 1995-2000 Russell King * @@ -39,6 +39,7 @@ subs r2, r2, #8 bmi .no_outsw_8 + .outsw_8_lp: ldmia r1!, {r3, r4, r5, r6} mov ip, r3, lsl #16 @@ -75,6 +76,7 @@ subs r2, r2, #8 bpl .outsw_8_lp + tst r2, #7 LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) @@ -121,5 +123,3 @@ strne ip, [r0] LOADREGS(fd, sp!, {r4, r5, r6, pc}) - - diff -u --recursive --new-file v2.4.1/linux/arch/arm/lib/io-writesw-armv4.S linux/arch/arm/lib/io-writesw-armv4.S --- v2.4.1/linux/arch/arm/lib/io-writesw-armv4.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/lib/io-writesw-armv4.S Thu Feb 8 16:32:44 2001 @@ -1,5 +1,5 @@ /* - * linux/arch/arm/lib/io-readsb.S + * linux/arch/arm/lib/io-writesw-armv4.S * * Copyright (C) 1995-2000 Russell King * @@ -32,11 +32,11 @@ tst r1, #3 bne .outsw_align + stmfd sp!, {r4, r5, lr} + subs r2, r2, #8 bmi .no_outsw_8 - stmfd sp!, {r4, r5, lr} - .outsw_8_lp: ldmia r1!, {r3, r4, r5, ip} strh r3, [r0] @@ -54,26 +54,31 @@ subs r2, r2, #8 bpl .outsw_8_lp - ldmfd sp!, {r4, r5, lr} + tst r2, #7 - RETINSTR(moveq, pc, lr) + LOADREGS(eqfd, sp!, {r4, r5, pc}) .no_outsw_8: tst r2, #4 - ldmneia r1!, {r3, ip} - strneh r3, [r0] - movne r3, r3, lsr #16 - strneh r3, [r0] - strneh ip, [r0] - movne ip, ip, lsr #16 - strneh ip, [r0] - tst r2, #2 - ldrne r3, [r1], #4 - strneh r3, [r0] - movne r3, r3, lsr #16 - strneh r3, [r0] - tst r2, #1 + beq .no_outsw_4 + + ldmia r1!, {r3, ip} + strh r3, [r0] + mov r3, r3, lsr #16 + strh r3, [r0] + strh ip, [r0] + mov ip, ip, lsr #16 + strh ip, [r0] + +.no_outsw_4: tst r2, #2 + beq .no_outsw_2 + + ldr r3, [r1], #4 + strh r3, [r0] + mov r3, r3, lsr #16 + strh r3, [r0] + +.no_outsw_2: tst r2, #1 ldrneh r3, [r1] strneh r3, [r0] - RETINSTR(mov, pc, lr) - + LOADREGS(fd, sp!, {r4, r5, pc}) diff -u --recursive --new-file v2.4.1/linux/arch/arm/mach-sa1100/Makefile linux/arch/arm/mach-sa1100/Makefile --- v2.4.1/linux/arch/arm/mach-sa1100/Makefile Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mach-sa1100/Makefile Thu Feb 8 16:32:44 2001 @@ -20,15 +20,4 @@ obj-$(CONFIG_LEDS) += leds.o -# Files that are both resident and modular; remove from modular. - -obj-m := $(filter-out $(obj-y), $(obj-m)) - -# Translate to Rules.make lists. - -O_OBJS := $(filter-out $(export-objs), $(obj-y)) -OX_OBJS := $(filter $(export-objs), $(obj-y)) -M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) - include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/arm/mach-sa1100/hw.c linux/arch/arm/mach-sa1100/hw.c --- v2.4.1/linux/arch/arm/mach-sa1100/hw.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mach-sa1100/hw.c Thu Feb 8 16:32:44 2001 @@ -90,12 +90,12 @@ void clr_bitsy_egpio(unsigned long x) { bitsy_egpio &= ~x; - *(volatile int *)0xdc000000 = bitsy_egpio; + BITSY_EGPIO = bitsy_egpio; } void set_bitsy_egpio(unsigned long x) { bitsy_egpio |= x; - *(volatile int *)0xdc000000 = bitsy_egpio; + BITSY_EGPIO = bitsy_egpio; } EXPORT_SYMBOL(clr_bitsy_egpio); EXPORT_SYMBOL(set_bitsy_egpio); @@ -119,8 +119,8 @@ /* First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: * (SA-1110 Developer's Manual, section 9.1.2.1) */ - GAFR |= GPIO_GPIO27; - GPDR |= GPIO_GPIO27; + GAFR |= GPIO_32_768kHz; + GPDR |= GPIO_32_768kHz; TUCR = TUCR_3_6864MHz; /* Now, set up the PLL and RCLK in the SA-1111: */ @@ -133,32 +133,32 @@ * using the SKPCR. */ - { - /* - * SA1111 DMA bus master setup + /* If the system is going to use the SA-1111 DMA engines, set up + * the memory bus request/grant pins. Also configure the shared + * memory controller on the SA-1111 (SA-1111 Developer's Manual, + * section 3.2.3) and power up the DMA bus clock: */ - int cas; + if(machine_is_assabet()){ - /* SA1111 side */ - switch ( (MDCNFG>>12) & 0x03 ) { - case 0x02: - cas = 0; break; - case 0x03: - cas = 1; break; - default: - cas = 1; break; - } - SMCR = 1 /* 1: memory is SDRAM */ - | ( 1 << 1 ) /* 1:MBGNT is enable */ - | ( ((MDCNFG >> 4) & 0x07) << 2 ) /* row address lines */ - | ( cas << 5 ); /* CAS latency */ - - /* SA1110 side */ - GPDR |= 1<<21; - GPDR &= ~(1<<22); - GAFR |= ( (1<<21) | (1<<22) ); + GAFR |= (GPIO_MBGNT | GPIO_MBREQ); + GPDR |= GPIO_MBGNT; + GPDR &= ~GPIO_MBREQ; + TUCR |= TUCR_MR; + + /* Assabet is populated by default with two Samsung KM416S8030T-G8 + * 128Mb SDRAMs, which are organized as 12-bit (row addr) x 9-bit + * (column addr), according to the data sheet. Apparently, the + * bank selects factor into the row address, as Angel sets up the + * SA-1110 to use 14x9 addresses. The SDRAM datasheet specifies + * that when running at 100-125MHz, the CAS latency for -8 parts + * is 3 cycles, which is consistent with Angel. + */ + + SMCR = (SMCR_DTIM | SMCR_MBGE | + FInsrt(FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), SMCR_DRAC) | + ((FExtr(MDCNFG, MDCNFG_SA1110_TDL0)==3) ? SMCR_CLAT : 0)); - TUCR |= (1<<10); + SKPCR |= SKPCR_DCLKEN; } } diff -u --recursive --new-file v2.4.1/linux/arch/arm/mach-shark/Makefile linux/arch/arm/mach-shark/Makefile --- v2.4.1/linux/arch/arm/mach-shark/Makefile Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mach-shark/Makefile Thu Feb 8 16:32:44 2001 @@ -5,6 +5,8 @@ # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). +USE_STANDARD_AS_RULE := true + O_TARGET := shark.o # Object file lists. @@ -17,16 +19,5 @@ export-objs := #obj-$(CONFIG_LEDS) += leds.o - -# Files that are both resident and modular; remove from modular. - -obj-m := $(filter-out $(obj-y), $(obj-m)) - -# Translate to Rules.make lists. - -O_OBJS := $(filter-out $(export-objs), $(obj-y)) -OX_OBJS := $(filter $(export-objs), $(obj-y)) -M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.4.1/linux/arch/arm/mm/Makefile Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/Makefile Thu Feb 8 16:32:44 2001 @@ -9,12 +9,11 @@ USE_STANDARD_AS_RULE := true -EXTRA_AFLAGS := -traditional O_TARGET := mm.o # Object file lists. -obj-y := extable.o fault-$(PROCESSOR).o init.o \ +obj-y := extable.o fault-common.o fault-$(PROCESSOR).o init.o \ mm-$(PROCESSOR).o small_page.o obj-m := obj-n := @@ -22,10 +21,10 @@ export-objs := proc-syms.o p-$(CONFIG_CPU_26) += proc-arm2,3.o -p-$(CONFIG_CPU_ARM6) += proc-arm6,7.o -p-$(CONFIG_CPU_ARM7) += proc-arm6,7.o -p-$(CONFIG_CPU_ARM720) += proc-arm720.o -p-$(CONFIG_CPU_ARM920) += proc-arm920.o +p-$(CONFIG_CPU_ARM610) += proc-arm6,7.o +p-$(CONFIG_CPU_ARM710) += proc-arm6,7.o +p-$(CONFIG_CPU_ARM720T) += proc-arm720.o +p-$(CONFIG_CPU_ARM920T) += proc-arm920.o p-$(CONFIG_CPU_ARM10) += proc-arm10.o p-$(CONFIG_CPU_SA110) += proc-sa110.o p-$(CONFIG_CPU_SA1100) += proc-sa110.o @@ -37,29 +36,16 @@ # Integrator follows "new style" # Soon, others will do too, and we can get rid of this -MMMACH := mm-$(MACHINE).o +MMMACH := mm-$(MACHINE).c ifeq ($(MMMACH),$(wildcard $(MMMACH))) -obj-$(CONFIG_CPU_32) += $(MMMACH) +obj-$(CONFIG_CPU_32) += $(MMMACH:.c=.o) endif obj-y += $(sort $(p-y)) -# Files that are both resident and modular; remove from modular. - -obj-m := $(filter-out $(obj-y), $(obj-m)) - -# Translate to Rules.make lists. - -O_OBJS := $(filter-out $(export-objs), $(obj-y)) -OX_OBJS := $(filter $(export-objs), $(obj-y)) -M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) -MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) - include $(TOPDIR)/Rules.make # Special dependencies -fault-armv.o: fault-common.c -fault-armo.o: fault-common.c proc-arm2,3.o: ../lib/constants.h proc-arm6,7.o: ../lib/constants.h proc-arm720.o: ../lib/constants.h diff -u --recursive --new-file v2.4.1/linux/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c --- v2.4.1/linux/arch/arm/mm/fault-armo.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/fault-armo.c Thu Feb 8 16:32:44 2001 @@ -23,14 +23,20 @@ #include #include -#define FAULT_CODE_FORCECOW 0x80 +#define FAULT_CODE_LDRSTRPOST 0x80 +#define FAULT_CODE_LDRSTRPRE 0x40 +#define FAULT_CODE_LDRSTRREG 0x20 +#define FAULT_CODE_LDMSTM 0x10 +#define FAULT_CODE_LDCSTC 0x08 #define FAULT_CODE_PREFETCH 0x04 #define FAULT_CODE_WRITE 0x02 +#define FAULT_CODE_FORCECOW 0x01 #define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) #define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) -#include "fault-common.c" +extern int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs); +extern void show_pte(struct mm_struct *mm, unsigned long addr); /* * Handle a data abort. Note that we have to handle a range of addresses diff -u --recursive --new-file v2.4.1/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c --- v2.4.1/linux/arch/arm/mm/fault-armv.c Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/fault-armv.c Thu Feb 8 16:32:44 2001 @@ -27,27 +27,9 @@ #include #include -#define FAULT_CODE_READ 0x02 - -#define DO_COW(m) (!((m) & FAULT_CODE_READ)) -#define READ_FAULT(m) ((m) & FAULT_CODE_READ) - extern void die_if_kernel(const char *str, struct pt_regs *regs, int err); - -#include "fault-common.c" - -#ifdef DEBUG -static int sp_valid(unsigned long *sp) -{ - unsigned long addr = (unsigned long) sp; - - if (addr >= 0xb0000000 && addr < 0xd0000000) - return 1; - if (addr >= 0x03ff0000 && addr < 0x04000000) - return 1; - return 0; -} -#endif +extern void show_pte(struct mm_struct *mm, unsigned long addr); +extern int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs); #ifdef CONFIG_ALIGNMENT_TRAP /* @@ -178,6 +160,15 @@ eaddr -= offset.un; } + /* + * This is a "hint" - we already have eaddr worked out by the + * processor for us. + */ + if (addr != eaddr) + printk(KERN_ERR "LDRHSTRH: PC = %08lx, instr = %08x, " + "addr = %08lx, eaddr = %08lx\n", + instruction_pointer(regs), instr, addr, eaddr); + if (LDST_L_BIT(instr)) regs->uregs[rd] = get_unaligned((unsigned short *)eaddr); else @@ -253,8 +244,15 @@ } } -if (addr != eaddr) -printk("PC = %08lx, instr = %08x, addr = %08lx, eaddr = %08lx\n", instruction_pointer(regs), instr, addr, eaddr); + /* + * This is a "hint" - we already have eaddr worked out by the + * processor for us. + */ + if (addr != eaddr) + printk(KERN_ERR "LDRSTR: PC = %08lx, instr = %08x, " + "addr = %08lx, eaddr = %08lx\n", + instruction_pointer(regs), instr, addr, eaddr); + if (LDST_L_BIT(instr)) { regs->uregs[rd] = get_unaligned((unsigned long *)eaddr); if (rd == 15) @@ -284,6 +282,15 @@ if (!LDST_U_BIT(instr)) eaddr -= nr_regs; + /* + * This is a "hint" - we already have eaddr worked out by the + * processor for us. + */ + if (addr != eaddr) + printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08x, " + "addr = %08lx, eaddr = %08lx\n", + instruction_pointer(regs), instr, addr, eaddr); + if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) || (LDST_U_BIT(instr) && LDST_P_BIT(instr))) eaddr += 4; @@ -322,39 +329,39 @@ #endif -#ifdef CONFIG_DEBUG_USER - +/* + * Some section permission faults need to be handled gracefully, for + * instance, when they happen due to a __{get,put}_user during an oops). + * In this case, we should return an error to the __{get,put}_user caller + * instead of causing another oops. We should also fixup this fault as + * the user could pass a pointer to a section to the kernel. + */ static int do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs) { + unsigned long fixup; + if (user_mode(regs)) { +#ifdef CONFIG_DEBUG_USER printk("%s: permission fault on section, " "address=0x%08lx, code %d\n", current->comm, addr, error_code); +#endif + goto fail; + } + + fixup = search_exception_table(instruction_pointer(regs)); + if (fixup != 0) { #ifdef DEBUG - { - unsigned int i, j; - unsigned long *sp; - - sp = (unsigned long *) (regs->ARM_sp - 128); - for (j = 0; j < 20 && sp_valid(sp); j++) { - printk("%p: ", sp); - for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++) - printk("%08lx ", *sp); - printk("\n"); - } - show_regs(regs); - c_backtrace(regs->ARM_fp, regs->ARM_cpsr); - } + printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n", + tsk->comm, regs->ARM_pc, addr, fixup); #endif + regs->ARM_pc = fixup; + return 0; } +fail: return 1; /* not fixed up */ } -#else - -#define do_sect_fault NULL - -#endif static const struct fsr_info { int (*fn)(unsigned long addr, int error_code, struct pt_regs *regs); @@ -382,18 +389,19 @@ /* * Currently dropped down to debug level */ -#define BUG_PROC_MSG \ - KERN_DEBUG "Weird data abort (%08X).\n" \ - KERN_DEBUG "Please see http://www.arm.linux.org.uk/state.html for " \ - "more information\n" - asmlinkage void do_DataAbort(unsigned long addr, int error_code, struct pt_regs *regs, int fsr) { const struct fsr_info *inf = fsr_info + (fsr & 15); +#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) if (addr == regs->ARM_pc) - goto weirdness; + goto sa1_weirdness; +#endif +#if defined(CONFIG_CPU_ARM720T) && defined(CONFIG_ALIGNMENT_TRAP) + if (addr & 3 && (fsr & 13) != 1) + goto arm720_weirdness; +#endif if (!inf->fn) goto bad; @@ -409,26 +417,51 @@ die_if_kernel("Oops", regs, 0); return; -weirdness: +#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) +sa1_weirdness: if (user_mode(regs)) { static int first = 1; if (first) - /* - * I want statistical information on this problem, - * but we don't want to hastle the users too much. - */ - printk(BUG_PROC_MSG, fsr); + printk(KERN_DEBUG "Weird data abort detected\n"); first = 0; return; } if (!inf->fn || inf->fn(addr, error_code, regs)) goto bad; + return; +#endif +#if defined(CONFIG_CPU_ARM720T) && defined(CONFIG_ALIGNMENT_TRAP) +arm720_weirdness: + if (!user_mode(regs)) { + unsigned long instr; + + instr = *(unsigned long *)instruction_pointer(regs); + + if ((instr & 0x04400000) != 0x04400000) { + static int first = 1; + if (first) + printk("Mis-reported alignment fault at " + "0x%08lx, fsr 0x%02x, code 0x%02x, " + "PC = 0x%08lx, instr = 0x%08lx\n", + addr, fsr, error_code, regs->ARM_pc, + instr); + first = 0; + cpu_tlb_invalidate_all(); + cpu_cache_clean_invalidate_all(); + return; + } + } + + if (!inf->fn || inf->fn(addr, error_code, regs)) + goto bad; + return; +#endif } asmlinkage int do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) { - do_page_fault(addr, FAULT_CODE_READ, regs); + do_page_fault(addr, 0, regs); return 1; } diff -u --recursive --new-file v2.4.1/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c --- v2.4.1/linux/arch/arm/mm/fault-common.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/mm/fault-common.c Thu Feb 8 16:32:44 2001 @@ -9,8 +9,41 @@ * published by the Free Software Foundation. */ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_CPU_26 +#define FAULT_CODE_WRITE 0x02 +#define FAULT_CODE_FORCECOW 0x01 +#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) +#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) +#else +/* + * On 32-bit processors, we define "mode" to be zero when reading, + * non-zero when writing. This now ties up nicely with the polarity + * of the 26-bit machines, and also means that we avoid the horrible + * gcc code for "int val = !other_val;". + */ +#define DO_COW(m) (m) +#define READ_FAULT(m) (!(m)) +#endif -extern void die(const char *msg, struct pt_regs *regs, int err); +NORET_TYPE void die(const char *msg, struct pt_regs *regs, int err) ATTRIB_NORET; /* * This is useful to dump out the page tables associated with @@ -60,7 +93,9 @@ printk("\n"); } -static int __do_page_fault(struct mm_struct *mm, unsigned long addr, int mode, struct task_struct *tsk) +static int +__do_page_fault(struct mm_struct *mm, unsigned long addr, int mode, + struct task_struct *tsk) { struct vm_area_struct *vma; int fault, mask; @@ -159,7 +194,7 @@ return -2; } -static int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) +int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs) { struct task_struct *tsk; struct mm_struct *mm; @@ -278,8 +313,10 @@ * 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 %s at virtual address %08lx\n", - (addr < PAGE_SIZE) ? "NULL pointer dereference" : "paging request", addr); + printk(KERN_ALERT + "Unable to handle kernel %s at virtual address %08lx\n", + (addr < PAGE_SIZE) ? "NULL pointer dereference" : + "paging request", addr); show_pte(mm, addr); die("Oops", regs, mode); diff -u --recursive --new-file v2.4.1/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.4.1/linux/arch/arm/mm/init.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/mm/init.c Thu Feb 8 16:32:44 2001 @@ -49,7 +49,7 @@ #define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *)) static unsigned long totalram_pages; -pgd_t swapper_pg_dir[PTRS_PER_PGD]; +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern char _stext, _text, _etext, _end, __init_begin, __init_end; /* @@ -418,7 +418,7 @@ if (machine_is_archimedes() || machine_is_a5k()) reserve_bootmem_node(pgdat, 0x02000000, 0x00080000); if (machine_is_p720t()) - reserve_bootmem_node(pgdat, 0xc0000000, 0x00014000); + reserve_bootmem_node(pgdat, PAGE_OFFSET, 0x00014000); } /* @@ -450,8 +450,28 @@ initrd_node = check_initrd(mi); map_pg = bootmap_pfn; - - for (node = 0; node < numnodes; node++, np++) { + + /* + * Initialise the bootmem nodes. + * + * What we really want to do is: + * + * unmap_all_regions_except_kernel(); + * for_each_node_in_reverse_order(node) { + * map_node(node); + * allocate_bootmem_map(node); + * init_bootmem_node(node); + * free_bootmem_node(node); + * } + * + * but this is a 2.5-type change. For now, we just set + * the nodes up in reverse order. + * + * (we could also do with rolling bootmem_init and paging_init + * into one generic "memory_init" type function). + */ + np += numnodes - 1; + for (node = numnodes - 1; node >= 0; node--, np--) { /* * If there are no pages in this node, ignore it. * Note that node 0 must always have some pages. diff -u --recursive --new-file v2.4.1/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c --- v2.4.1/linux/arch/arm/mm/mm-armv.c Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/mm/mm-armv.c Thu Feb 8 16:32:44 2001 @@ -275,7 +275,7 @@ off = md->physical - virt; length = md->length; - while ((virt & 1048575 || (virt + off) & 1048575) && length >= PAGE_SIZE) { + while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) { alloc_init_page(virt, virt + off, md->domain, prot_pte); virt += PAGE_SIZE; diff -u --recursive --new-file v2.4.1/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S --- v2.4.1/linux/arch/arm/mm/proc-arm6,7.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/proc-arm6,7.S Thu Feb 8 16:32:44 2001 @@ -7,10 +7,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * MMU functions for ARM6 - * * These are the low level assembler for performing cache and TLB - * functions on the ARM6 & ARM7. + * functions on the ARM610 & ARM710. */ #include #include @@ -105,9 +103,9 @@ ENTRY(cpu_arm6_data_abort) ldr r4, [r0] @ read instruction causing problem - mov r1, r4, lsr #19 @ r1 b1 = L + tst r4, r4, lsr #21 @ C = bit 20 + sbc r1, r1, r1 @ r1 = C - 1 and r2, r4, #14 << 24 - and r1, r1, #2 @ check read/write bit teq r2, #8 << 24 @ was it ldm/stm bne Ldata_simple @@ -138,9 +136,9 @@ ENTRY(cpu_arm7_data_abort) ldr r4, [r0] @ read instruction causing problem - mov r1, r4, lsr #19 @ r1 b1 = L + tst r4, r4, lsr #21 @ C = bit 20 + sbc r1, r1, r1 @ r1 = C - 1 and r2, r4, #15 << 24 - and r1, r1, #2 @ check read/write bit add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine movs pc, lr diff -u --recursive --new-file v2.4.1/linux/arch/arm/mm/proc-arm720.S linux/arch/arm/mm/proc-arm720.S --- v2.4.1/linux/arch/arm/mm/proc-arm720.S Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/mm/proc-arm720.S Thu Feb 8 16:32:44 2001 @@ -144,9 +144,9 @@ ENTRY(cpu_arm720_data_abort) ldr r4, [r0] @ read instruction causing problem - mov r1, r4, lsr #19 @ r1 b1 = L + tst r4, r4, lsr #21 @ C = bit 20 + sbc r1, r1, r1 @ r1 = C - 1 and r2, r4, #15 << 24 - and r1, r1, #2 @ check read/write bit add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine movs pc, lr @@ -283,23 +283,11 @@ ldmfd sp!, {pc} /* - * Function: arm720_proc_do_idle (void) - * - * Params : r0 = call type: - * 0 = slow idle - * 1 = fast idle - * 2 = switch to slow processor clock - * 3 = switch to fast processor clock - * + * Function: arm720_proc_do_idle(void) + * Params : r0 = unused * Purpose : put the processer in proper idle mode */ ENTRY(cpu_arm720_do_idle) -#if 0 /* FIXME: is this part of the processor? */ - ldr r2, =IO_BASE @ Virt addr of IO - add r2, r2, #0x00050000 @ Start of PMU regs - mov r1, #0x01 @ Idle mode - str r1, [r2, #4] -#endif mov pc, lr /* diff -u --recursive --new-file v2.4.1/linux/arch/arm/mm/proc-arm920.S linux/arch/arm/mm/proc-arm920.S --- v2.4.1/linux/arch/arm/mm/proc-arm920.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/proc-arm920.S Thu Feb 8 16:32:44 2001 @@ -68,9 +68,9 @@ ENTRY(cpu_arm920_data_abort) ldr r1, [r0] @ read aborted instruction mrc p15, 0, r0, c6, c0, 0 @ get FAR - mov r1, r1, lsr #19 @ b1 = L + tst r1, r1, lsr #21 @ C = bit 20 mrc p15, 0, r3, c5, c0, 0 @ get FSR - and r1, r1, #2 + sbc r1, r1, r1 @ r1 = C - 1 and r3, r3, #255 mov pc, lr @@ -330,7 +330,7 @@ mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain WB ENTRY(cpu_arm920_icache_invalidate_page) - /* why no invalidate I cache --rmk */ + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache mov pc, lr diff -u --recursive --new-file v2.4.1/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.4.1/linux/arch/arm/mm/proc-sa110.S Mon Sep 18 15:15:25 2000 +++ linux/arch/arm/mm/proc-sa110.S Thu Feb 8 16:32:44 2001 @@ -83,9 +83,9 @@ ENTRY(cpu_sa1100_data_abort) ldr r1, [r0] @ read aborted instruction mrc p15, 0, r0, c6, c0, 0 @ get FAR - mov r1, r1, lsr #19 @ b1 = L + tst r1, r1, lsr #21 @ C = bit 20 mrc p15, 0, r3, c5, c0, 0 @ get FSR - and r1, r1, #2 + sbc r1, r1, r1 @ r1 = C - 1 and r3, r3, #255 mov pc, lr diff -u --recursive --new-file v2.4.1/linux/arch/arm/nwfpe/Makefile linux/arch/arm/nwfpe/Makefile --- v2.4.1/linux/arch/arm/nwfpe/Makefile Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/nwfpe/Makefile Thu Feb 8 16:32:44 2001 @@ -6,27 +6,27 @@ USE_STANDARD_AS_RULE := true -NWFPE_OBJS := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \ - fpmodule.o fpopcode.o softfloat.o \ - single_cpdo.o double_cpdo.o extended_cpdo.o +O_TARGET := math-emu.o -ifeq ($(CONFIG_CPU_26),y) -NWFPE_OBJS += entry26.o -else -NWFPE_OBJS += entry.o -endif +obj-y := +obj-m := +obj-n := + +list-multi := nwfpe.o -ifeq ($(CONFIG_NWFPE),y) -O_TARGET := math-emu.o -O_OBJS = $(NWFPE_OBJS) +obj-$(CONFIG_NWFPE) += nwfpe.o + +nwfpe-objs := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \ + fpmodule.o fpopcode.o softfloat.o \ + single_cpdo.o double_cpdo.o extended_cpdo.o + +ifeq ($(CONFIG_CPU_26),y) +nwfpe-objs += entry26.o else - ifeq ($(CONFIG_NWFPE),m) - M_OBJS = nwfpe.o - MI_OBJS = $(NWFPE_OBJS) - endif +nwfpe-objs += entry.o endif include $(TOPDIR)/Rules.make -nwfpe.o: $(MI_OBJS) $(MIX_OBJS) - $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS) +nwfpe.o: $(nwfpe-objs) + $(LD) -r -o $@ $(nwfpe-objs) diff -u --recursive --new-file v2.4.1/linux/arch/arm/vmlinux-armo.lds.in linux/arch/arm/vmlinux-armo.lds.in --- v2.4.1/linux/arch/arm/vmlinux-armo.lds.in Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/vmlinux-armo.lds.in Thu Feb 8 16:32:44 2001 @@ -47,6 +47,8 @@ *(.gnu.warning) *(.text.lock) /* out-of-line lock text */ *(.rodata) + *(.glue_7) + *(.glue_7t) *(.kstrtab) . = ALIGN(16); /* Exception table */ __start___ex_table = .; diff -u --recursive --new-file v2.4.1/linux/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in --- v2.4.1/linux/arch/arm/vmlinux-armv.lds.in Mon Nov 27 17:07:59 2000 +++ linux/arch/arm/vmlinux-armv.lds.in Thu Feb 8 16:32:44 2001 @@ -42,6 +42,8 @@ *(.gnu.warning) *(.text.lock) /* out-of-line lock text */ *(.rodata) + *(.glue_7) + *(.glue_7t) *(.kstrtab) . = ALIGN(16); __start___ex_table = .; /* Exception table */ diff -u --recursive --new-file v2.4.1/linux/arch/cris/Makefile linux/arch/cris/Makefile --- v2.4.1/linux/arch/cris/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/Makefile Thu Feb 8 16:32:44 2001 @@ -0,0 +1,96 @@ +# $Id: Makefile,v 1.11 2000/11/27 17:58:30 bjornw Exp $ +# cris/Makefile +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. + +LD_SCRIPT=$(TOPDIR)/arch/cris/cris.ld + +# A bug in ld prevents us from having a (constant-value) symbol in a +# "ORIGIN =" or "LENGTH =" expression. We fix that by generating a +# linker file with the symbolic part of those expressions evaluated. +# Unfortunately, there is trouble making vmlinux depend on anything we +# generate here, so we *always* regenerate the final linker script and +# replace the LD macro to get what we want. Thankfully(?) vmlinux is +# always rebuilt (due to calling make recursively and not knowing if +# anything was rebuilt). +# The shell script to build in some kind of dependency is really not +# necessary for reasons of speed. It's there because always +# regenerating stuff (even for incremental linking of subsystems!) is +# even more nauseating. +LD = if [ ! -e $(LD_SCRIPT).tmp -o $(LD_SCRIPT) -nt $(LD_SCRIPT).tmp ]; then \ + sed -e s/@ETRAX_DRAM_BASE@/0x$(ETRAX_DRAM_BASE)/ \ + -e s/@ETRAX_DRAM_SIZE_M@/$(ETRAX_DRAM_SIZE)/ \ + < $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \ + else true; \ + fi && $(CROSS_COMPILE)ld -mcriself + +LINKFLAGS =-qmagic -mcriself -T $(LD_SCRIPT).tmp + +# objcopy is used to make binary images from the resulting linked file + +OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S + +# normally, gcc on a linux box adds __linux__ but we do it "manually" +# gcc-cris defaults to a.out, we need ELF, so -melf + +CFLAGS := $(CFLAGS) -march=v10 -fno-strict-aliasing -pipe -D__linux__ + +ifdef CONFIG_KGDB +CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g +CFLAGS += -fno-omit-frame-pointer +endif + +HEAD := arch/cris/kernel/head.o + +SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers +CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o +LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a) +LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC) + +arch/cris/kernel: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/cris/kernel + +arch/cris/mm: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/cris/mm + +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot + +vmlinux.bin: vmlinux + $(OBJCOPY) vmlinux vmlinux.bin + +timage: vmlinux.bin + cat vmlinux.bin cramfs.img >timage + +simimage: timage + cp vmlinux.bin simvmlinux.bin + +# the following will remake timage without compiling the kernel +# it does of course require that all object files exist... + +cramfs: +## cramfs - Creates a cramfs image + mkcramfs -p 8192 root cramfs.img + cat vmlinux.bin cramfs.img >timage + +zImage: vmlinux +## zImage - Compressed kernel (gzip) + @$(MAKEBOOT) zImage + +compressed: zImage + +archclean: + @$(MAKEBOOT) clean + rm -f timage vmlinux.bin cramfs.img + rm -rf $(LD_SCRIPT).tmp + +archmrproper: + +archdep: + @$(MAKEBOOT) dep diff -u --recursive --new-file v2.4.1/linux/arch/cris/README.mm linux/arch/cris/README.mm --- v2.4.1/linux/arch/cris/README.mm Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/README.mm Thu Feb 8 16:32:44 2001 @@ -0,0 +1,241 @@ +Memory management for CRIS/MMU +------------------------------ +HISTORY: + +$Log: README.mm,v $ +Revision 1.1 2000/07/10 16:25:21 bjornw +Initial revision + +Revision 1.4 2000/01/17 02:31:59 bjornw +Added discussion of paging and VM. + +Revision 1.3 1999/12/03 16:43:23 hp +Blurb about that the 3.5G-limitation is not a MMU limitation + +Revision 1.2 1999/12/03 16:04:21 hp +Picky comment about not mapping the first page + +Revision 1.1 1999/12/03 15:41:30 bjornw +First version of CRIS/MMU memory layout specification. + + + + + +------------------------------ + +See the ETRAX-NG HSDD for reference. + +We use the page-size of 8 kbytes, as opposed to the i386 page-size of 4 kbytes. + +The MMU can, apart from the normal mapping of pages, also do a top-level +segmentation of the kernel memory space. We use this feature to avoid having +to use page-tables to map the physical memory into the kernel's address +space. We also use it to keep the user-mode virtual mapping in the same +map during kernel-mode, so that the kernel easily can access the corresponding +user-mode process' data. + +As a comparision, the Linux/i386 2.0 puts the kernel and physical RAM at +address 0, overlapping with the user-mode virtual space, so that descriptor +registers are needed for each memory access to specify which MMU space to +map through. That changed in 2.2, putting the kernel/physical RAM at +0xc0000000, to co-exist with the user-mode mapping. We will do something +quite similar, but with the additional complexity of having to map the +internal chip I/O registers and the flash memory area (including SRAM +and peripherial chip-selets). + +The kernel-mode segmentation map: + + ------------------------ ------------------------ +FFFFFFFF| | => cached | | + | kernel seg_f | flash | | +F0000000|______________________| | | +EFFFFFFF| | => uncached | | + | kernel seg_e | flash | | +E0000000|______________________| | DRAM | +DFFFFFFF| | paged to any | Un-cached | + | kernel seg_d | =======> | | +D0000000|______________________| | | +CFFFFFFF| | | | + | kernel seg_c |==\ | | +C0000000|______________________| \ |______________________| +BFFFFFFF| | uncached | | + | kernel seg_b |=====\=========>| Registers | +B0000000|______________________| \c |______________________| +AFFFFFFF| | \a | | + | | \c | FLASH/SRAM/Peripheral| + | | \h |______________________| + | | \e | | + | | \d | | + | kernel seg_0 - seg_a | \==>| DRAM | + | | | Cached | + | | paged to any | | + | | =======> |______________________| + | | | | + | | | Illegal | + | | |______________________| + | | | | + | | | FLASH/SRAM/Peripheral| +00000000|______________________| |______________________| + +In user-mode it looks the same except that only the space 0-AFFFFFFF is +available. Therefore, in this model, the virtual address space per process +is limited to 0xb0000000 bytes (minus 8192 bytes, since the first page, +0..8191, is never mapped, in order to trap NULL references). + +It also means that the total physical RAM that can be mapped is 256 MB +(kseg_c above). More RAM can be mapped by choosing a different segmentation +and shrinking the user-mode memory space. + +The MMU can map all 4 GB in user mode, but doing that would mean that a +few extra instructions would be needed for each access to user mode +memory. + +The kernel needs access to both cached and uncached flash. Uncached is +necessary because of the special write/erase sequences. Also, the +peripherial chip-selects are decoded from that region. + +The kernel also needs its own virtual memory space. That is kseg_d. It +is used by the vmalloc() kernel function to allocate virtual contiguous +chunks of memory not possible using the normal kmalloc physical RAM +allocator. + +The setting of the actual MMU control registers to use this layout would +be something like this: + +R_MMU_KSEG = ( ( seg_f, seg ) | // Flash cached + ( seg_e, seg ) | // Flash uncached + ( seg_d, page ) | // kernel vmalloc area + ( seg_c, seg ) | // kernel linear segment + ( seg_b, seg ) | // kernel linear segment + ( seg_a, page ) | + ( seg_9, page ) | + ( seg_8, page ) | + ( seg_7, page ) | + ( seg_6, page ) | + ( seg_5, page ) | + ( seg_4, page ) | + ( seg_3, page ) | + ( seg_2, page ) | + ( seg_1, page ) | + ( seg_0, page ) ); + +R_MMU_KBASE_HI = ( ( base_f, 0x0 ) | // flash/sram/periph cached + ( base_e, 0x8 ) | // flash/sram/periph uncached + ( base_d, 0x0 ) | // don't care + ( base_c, 0x4 ) | // physical RAM cached area + ( base_b, 0xb ) | // uncached on-chip registers + ( base_a, 0x0 ) | // don't care + ( base_9, 0x0 ) | // don't care + ( base_8, 0x0 ) ); // don't care + +R_MMU_KBASE_LO = ( ( base_7, 0x0 ) | // don't care + ( base_6, 0x0 ) | // don't care + ( base_5, 0x0 ) | // don't care + ( base_4, 0x0 ) | // don't care + ( base_3, 0x0 ) | // don't care + ( base_2, 0x0 ) | // don't care + ( base_1, 0x0 ) | // don't care + ( base_0, 0x0 ) ); // don't care + +NOTE: while setting up the MMU, we run in a non-mapped mode in the DRAM (0x40 +segment) and need to setup the seg_4 to a unity mapping, so that we don't get +a fault before we have had time to jump into the real kernel segment (0xc0). This +is done in head.S temporarily, but fixed by the kernel later in paging_init. + + +Paging - PTE's, PMD's and PGD's +------------------------------- + +[ References: asm/pgtable.h, asm/page.h, asm/mmu.h ] + +The paging mechanism uses virtual addresses to split a process memory-space into +pages, a page being the smallest unit that can be freely remapped in memory. On +Linux/CRIS, a page is 8192 bytes (for technical reasons not equal to 4096 as in +most other 32-bit architectures). It would be inefficient to let a virtual memory +mapping be controlled by a long table of page mappings, so it is broken down into +a 2-level structure with a Page Directory containing pointers to Page Tables which +each have maps of up to 2048 pages (8192 / sizeof(void *)). Linux can actually +handle 3-level structures as well, with a Page Middle Directory in between, but +in many cases, this is folded into a two-level structure by excluding the Middle +Directory. + +We'll take a look at how an address is translated while we discuss how it's handled +in the Linux kernel. + +The example address is 0xd004000c; in binary this is: + +31 23 15 7 0 +11010000 00000100 00000000 00001100 + +|______| |__________||____________| + PGD PTE page offset + +Given the top-level Page Directory, the offset in that directory is calculated +using the upper 8 bits: + +extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) +{ + return mm->pgd + (address >> PGDIR_SHIFT); +} + +PGDIR_SHIFT is the log2 of the amount of memory an entry in the PGD can map; in our +case it is 24, corresponding to 16 MB. This means that each entry in the PGD +corresponds to 16 MB of virtual memory. + +The pgd_t from our example will therefore be the 208'th (0xd0) entry in mm->pgd. + +Since the Middle Directory does not exist, it is a unity mapping: + +extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) +{ + return (pmd_t *) dir; +} + +The Page Table provides the final lookup by using bits 13 to 23 as index: + +extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address) +{ + return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & + (PTRS_PER_PTE - 1)); +} + +PAGE_SHIFT is the log2 of the size of a page; 13 in our case. PTRS_PER_PTE is +the number of pointers that fit in a Page Table and is used to mask off the +PGD-part of the address. + +The so-far unused bits 0 to 12 are used to index inside a page linearily. + +The VM system +------------- + +The kernels own page-directory is the swapper_pg_dir, cleared in paging_init, +and contains the kernels virtual mappings (the kernel itself is not paged - it +is mapped linearily using kseg_c as described above). Architectures without +kernel segments like the i386, need to setup swapper_pg_dir directly in head.S +to map the kernel itself. swapper_pg_dir is pointed to by init_mm.pgd as the +init-task's PGD. + +To see what support functions are used to setup a page-table, let's look at the +kernel's internal paged memory system, vmalloc/vfree. + +void * vmalloc(unsigned long size) + +The vmalloc-system keeps a paged segment in kernel-space at 0xd0000000. What +happens first is that a virtual address chunk is allocated to the request using +get_vm_area(size). After that, physical RAM pages are allocated and put into +the kernel's page-table using alloc_area_pages(addr, size). + +static int alloc_area_pages(unsigned long address, unsigned long size) + +First the PGD entry is found using init_mm.pgd. This is passed to +alloc_area_pmd (remember the 3->2 folding). It uses pte_alloc_kernel to +check if the PGD entry points anywhere - if not, a page table page is +allocated and the PGD entry updated. Then the alloc_area_pte function is +used just like alloc_area_pmd to check which page table entry is desired, +and a physical page is allocated and the table entry updated. All of this +is repeated at the top-level until the entire address range specified has +been mapped. + + + diff -u --recursive --new-file v2.4.1/linux/arch/cris/boot/Makefile linux/arch/cris/boot/Makefile --- v2.4.1/linux/arch/cris/boot/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/Makefile Thu Feb 8 16:32:44 2001 @@ -0,0 +1,14 @@ +# +# arch/cris/boot/Makefile +# + +zImage: compressed/vmlinuz + +compressed/vmlinuz: $(TOPDIR)/vmlinux + @$(MAKE) -C compressed vmlinuz + +dep: + +clean: + rm -f zImage tools/build compressed/vmlinux.out + @$(MAKE) -C compressed clean diff -u --recursive --new-file v2.4.1/linux/arch/cris/boot/compressed/Makefile linux/arch/cris/boot/compressed/Makefile --- v2.4.1/linux/arch/cris/boot/compressed/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/compressed/Makefile Thu Feb 8 16:32:44 2001 @@ -0,0 +1,37 @@ +# +# linux/arch/etrax100/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux files and romfs +# + +CC = gcc-cris -melf -I $(TOPDIR)/include +CFLAGS = -O2 +LD = ld-cris +OBJCOPY = objcopy-cris + +OBJECTS = head.o misc.o + +# files to compress +SYSTEM = $(TOPDIR)/vmlinux.bin + +all: vmlinuz + +vmlinuz: piggy.img $(OBJECTS) + $(LD) -mcriself -T decompress.ld -o decompress.o $(OBJECTS) + $(OBJCOPY) -O binary --remove-section=.bss decompress.o decompress.bin +# save it for mkprod in the topdir. + cp decompress.bin $(TOPDIR) + cat decompress.bin piggy.img $(TOPDIR)/cramfs.img > vmlinuz + rm -f piggy.img + +head.o: head.S + $(CC) -D__ASSEMBLY__ -traditional -c head.S -o head.o + +# gzip the kernel image + +piggy.img: $(SYSTEM) + cat $(SYSTEM) | gzip -f -9 > piggy.img + +clean: + rm -f piggy.img vmlinuz vmlinuz.o + diff -u --recursive --new-file v2.4.1/linux/arch/cris/boot/compressed/README linux/arch/cris/boot/compressed/README --- v2.4.1/linux/arch/cris/boot/compressed/README Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/compressed/README Thu Feb 8 16:32:44 2001 @@ -0,0 +1,25 @@ +Creation of the self-extracting compressed kernel image (vmlinuz) +----------------------------------------------------------------- +$Id: README,v 1.1 2000/11/22 17:20:46 bjornw Exp $ + +This can be slightly confusing because it's a process with many steps. + +The kernel object built by the arch/etrax100/Makefile, vmlinux, is split +by that makefile into text and data binary files, vmlinux.text and +vmlinux.data. + +Those files together with a ROM filesystem can be catted together and +burned into a flash or executed directly at the DRAM origin. + +They can also be catted together and compressed with gzip, which is what +happens in this makefile. Together they make up piggy.img. + +The decompressor is built into the file decompress.o. It is turned into +the binary file decompress.bin, which is catted together with piggy.img +into the file vmlinuz. It can be executed in an arbitrary place in flash. + +Be careful - it assumes some things about free locations in DRAM. It +assumes the DRAM starts at 0x40000000 and that it is at least 8 MB, +so it puts its code at 0x40700000, and initial stack at 0x40800000. + +-Bjorn diff -u --recursive --new-file v2.4.1/linux/arch/cris/boot/compressed/decompress.ld linux/arch/cris/boot/compressed/decompress.ld --- v2.4.1/linux/arch/cris/boot/compressed/decompress.ld Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/compressed/decompress.ld Thu Feb 8 16:32:44 2001 @@ -0,0 +1,26 @@ +MEMORY + { + dram : ORIGIN = 0x40700000, + LENGTH = 0x00100000 + } + +SECTIONS +{ + .text : + { + _stext = . ; + *(.text) + *(.rodata) + _etext = . ; + } > dram + .data : + { + *(.data) + _edata = . ; + } > dram + .bss : + { + *(.bss) + _end = ALIGN( 0x10 ) ; + } > dram +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/boot/compressed/head.S linux/arch/cris/boot/compressed/head.S --- v2.4.1/linux/arch/cris/boot/compressed/head.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/compressed/head.S Thu Feb 8 16:32:44 2001 @@ -0,0 +1,100 @@ +/* + * arch/etrax100/boot/compressed/head.S + * + * Copyright (C) 1999 Axis Communications AB + * + * Code that sets up the DRAM registers, calls the + * decompressor to unpack the piggybacked kernel, and jumps. + * + */ + +#include +#define ASSEMBLER_MACROS_ONLY +#include + + ;; Exported symbols + + .globl _input_data + + + .text + + nop + di + +#ifndef CONFIG_SVINTO_SIM + + ;; We need to setup the bus registers before we start using the DRAM + + move.d DEF_R_WAITSTATES, r0 + move.d r0, [R_WAITSTATES] + + move.d DEF_R_BUS_CONFIG, r0 + move.d r0, [R_BUS_CONFIG] + + move.d DEF_R_DRAM_CONFIG, r0 + move.d r0, [R_DRAM_CONFIG] + + move.d DEF_R_DRAM_TIMING, r0 + move.d r0, [R_DRAM_TIMING] + +#endif + + ;; Setup the stack to a suitably high address. + ;; We assume 8 MB is the minimum DRAM in an eLinux + ;; product and put the sp at the top for now. + + move.d 0x40800000, sp + + ;; Figure out where the compressed piggyback image is + ;; in the flash (since we wont try to copy it to DRAM + ;; before unpacking). It is at _edata, but in flash. + ;; Use (_edata - basse) as offset to the current PC. + +basse: move.d pc, r5 + and.d 0x7fffffff, r5 ; strip any non-cache bit + subq 2, r5 ; compensate for the move.d pc instr + move.d r5, r0 ; save for later - flash address of 'basse' + add.d _edata, r5 + sub.d basse, r5 ; r5 = flash address of '_edata' + + ;; Copy text+data to DRAM + + move.d basse, r1 ; destination + move.d _edata, r2 ; end destination +1: move.w [r0+], r3 + move.w r3, [r1+] + cmp.d r2, r1 + bcs 1b + nop + + move.d r5, [_input_data] ; for the decompressor + + ;; Clear the decompressors BSS (between _edata and _end) + + moveq 0, r0 + move.d _edata, r1 + move.d _end, r2 +1: move.w r0, [r1+] + cmp.d r2, r1 + bcs 1b + nop + + ;; Do the decompression and save compressed size in _inptr + + jsr _decompress_kernel + + ;; Put start address of cramfs in r9 so the kernel can use it + ;; when mounting from flash + + move.d [_input_data], r9 ; flash address of compressed kernel + add.d [_inptr], r9 ; size of compressed kernel + + ;; Enter the decompressed kernel + + jump 0x40004000 ; kernel is linked to this address + + .data + +_input_data: + .dword 0 ; used by the decompressor diff -u --recursive --new-file v2.4.1/linux/arch/cris/boot/compressed/misc.c linux/arch/cris/boot/compressed/misc.c --- v2.4.1/linux/arch/cris/boot/compressed/misc.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/boot/compressed/misc.c Tue Feb 13 14:13:43 2001 @@ -0,0 +1,260 @@ +/* + * misc.c + * + * $Id: misc.c,v 1.3 2001/01/17 15:54:18 jonashg Exp $ + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * puts by Nick Holloway 1993, better puts by Martin Mares 1995 + * adoptation for Linux/CRIS Axis Communications AB, 1999 + * + */ + +/* where the piggybacked kernel image expects itself to live. + * it is the same address we use when we network load an uncompressed + * image into DRAM, and it is the address the kernel is linked to live + * at by etrax100.ld. + */ + +#define KERNEL_LOAD_ADR 0x40004000 + +#include +#include +#include + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +void* memset(void* s, int c, size_t n); +void* memcpy(void* __dest, __const void* __src, + size_t __n); + +#define memzero(s, n) memset ((s), 0, (n)) + + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +unsigned inptr = 0; /* index of next byte to be processed in inbuf + * After decompression it will contain the + * compressed size, and head.S will read it. + */ + +static unsigned outcnt = 0; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() inbuf[inptr++] + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern char *input_data; /* lives in head.S */ + +static long bytes_out = 0; +static uch *output_data; +static unsigned long output_ptr = 0; + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +static void puts(const char *); + +/* the "heap" is put directly after the BSS ends, at end */ + +extern int end; +static long free_mem_ptr = (long)&end; + +#include "../../../../lib/inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +/* decompressor info and error messages to serial console */ + +static void +puts(const char *s) +{ +#ifndef CONFIG_DEBUG_PORT_NULL + while(*s) { +#ifdef CONFIG_DEBUG_PORT0 + while(!(*R_SERIAL0_STATUS & (1 << 5))) ; + *R_SERIAL0_TR_DATA = *s++; +#endif +#ifdef CONFIG_DEBUG_PORT1 + while(!(*R_SERIAL1_STATUS & (1 << 5))) ; + *R_SERIAL1_TR_DATA = *s++; +#endif +#ifdef CONFIG_DEBUG_PORT2 + while(!(*R_SERIAL2_STATUS & (1 << 5))) ; + *R_SERIAL2_TR_DATA = *s++; +#endif +#ifdef CONFIG_DEBUG_PORT3 + while(!(*R_SERIAL3_STATUS & (1 << 5))) ; + *R_SERIAL3_TR_DATA = *s++; +#endif + } +#endif +} + +void* +memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void +error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted\n"); + + while(1); /* Halt */ +} + +void +setup_normal_output_buffer() +{ + output_data = (char *)KERNEL_LOAD_ADR; +} + +void +decompress_kernel() +{ + /* input_data is set in head.S */ + inbuf = input_data; + +#ifdef CONFIG_DEBUG_PORT0 + *R_SERIAL0_XOFF = 0; + *R_SERIAL0_BAUD = 0x99; + *R_SERIAL0_TR_CTRL = 0x40; +#endif +#ifdef CONFIG_DEBUG_PORT1 + *R_SERIAL1_XOFF = 0; + *R_SERIAL1_BAUD = 0x99; + *R_SERIAL1_TR_CTRL = 0x40; +#endif +#ifdef CONFIG_DEBUG_PORT2 + *R_SERIAL2_XOFF = 0; + *R_SERIAL2_BAUD = 0x99; + *R_SERIAL2_TR_CTRL = 0x40; +#endif +#ifdef CONFIG_DEBUG_PORT3 + *R_SERIAL3_XOFF = 0; + *R_SERIAL3_BAUD = 0x99; + *R_SERIAL3_TR_CTRL = 0x40; +#endif + + setup_normal_output_buffer(); + + makecrc(); + puts("Uncompressing Linux...\n"); + gunzip(); + puts("Done. Now booting the kernel.\n"); +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/config.in linux/arch/cris/config.in --- v2.4.1/linux/arch/cris/config.in Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/config.in Fri Feb 16 15:53:08 2001 @@ -0,0 +1,223 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +mainmenu_name "Linux/CRIS Kernel Configuration" + +define_bool CONFIG_UID16 y + +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 'General setup' + +bool 'Networking support' CONFIG_NET +bool 'System V IPC' CONFIG_SYSVIPC + +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA +fi + +bool 'Use kernel gdb debugger' CONFIG_KGDB + +bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG + +bool 'Use serial console (on the debug port)' CONFIG_USE_SERIAL_CONSOLE + +bool 'Use in-kernel ifconfig/route setup' CONFIG_KERNEL_IFCONFIG + +endmenu + +mainmenu_option next_comment +comment 'Hardware setup' + +choice 'Processor type' \ + "Etrax-100-LX CONFIG_ETRAX100LX \ + Etrax-100-LX-for-xsim-simulator CONFIG_SVINTO_SIM" Etrax-100-LX + +# For both LX version 1 and the current simulator we enable the low VM mapping +# Later when LX version 2 and above exist, this should be done with an if + +define_bool CONFIG_CRIS_LOW_MAP y + +hex 'DRAM base (hex)' ETRAX_DRAM_BASE 40000000 +int 'DRAM size (dec, in MB)' ETRAX_DRAM_SIZE 8 + +int 'Max possible flash size (dec, in MB)' CONFIG_ETRAX_FLASH_LENGTH 2 +int 'Buswidth of flash in bytes' CONFIG_ETRAX_FLASH_BUSWIDTH 2 + +choice 'Product LED port' \ + "Port-PA-LEDs CONFIG_ETRAX_PA_LEDS \ + Port-PB-LEDs CONFIG_ETRAX_PB_LEDS \ + Mem-0x90000000-LEDs CONFIG_ETRAX_90000000_LEDS \ + None CONFIG_ETRAX_NO_LEDS" Port-PA-LEDs + +if [ "$CONFIG_ETRAX_NO_LEDS" != "y" ]; then + int ' First green LED bit' CONFIG_ETRAX_LED1G 2 + int ' First red LED bit' CONFIG_ETRAX_LED1R 3 + int ' Second green LED bit' CONFIG_ETRAX_LED2G 4 + int ' Second red LED bit' CONFIG_ETRAX_LED2R 5 + int ' Third green LED bit' CONFIG_ETRAX_LED3R 2 + int ' Third red LED bit' CONFIG_ETRAX_LED3G 2 +fi + +choice 'Product debug-port' \ + "Serial-0 CONFIG_DEBUG_PORT0 \ + Serial-1 CONFIG_DEBUG_PORT1 \ + Serial-2 CONFIG_DEBUG_PORT2 \ + Serial-3 CONFIG_DEBUG_PORT3" Serial-0 + +hex 'R_WAITSTATES' DEF_R_WAITSTATES 95a6 +hex 'R_BUS_CONFIG' DEF_R_BUS_CONFIG 104 +hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040 +hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611 +hex 'R_PORT_PA_DIR' DEF_R_PORT_PA_DIR 1c +hex 'R_PORT_PA_DATA' DEF_R_PORT_PA_DATA 00 +hex 'R_PORT_PB_CONFIG' DEF_R_PORT_PB_CONFIG 00 +hex 'R_PORT_PB_DIR' DEF_R_PORT_PB_DIR 00 +hex 'R_PORT_PB_DATA' DEF_R_PORT_PB_DATA ff + +endmenu + +# only configure IP numbers if the kernel ifconfig/route setup is enabled + +if [ "$CONFIG_KERNEL_IFCONFIG" = "y" ]; then + mainmenu_option next_comment + comment 'IP address selection' + + comment 'All addresses are in hexadecimal form without 0x prefix' + + hex 'IP address' ELTEST_IPADR ab1005af + hex 'Network' ELTEST_NETWORK ab100000 + hex 'Netmask' ELTEST_NETMASK ffff0000 + hex 'Broadcast' ELTEST_BROADCAST ab10ffff + hex 'Gateway' ELTEST_GATEWAY ab100101 + hwaddr 'Ethernet address' ELTEST_ETHADR 00408ccd0000 + + endmenu +fi + +# bring in Etrax built-in drivers + +source arch/cris/drivers/Config.in + +# standard linux drivers + +source drivers/mtd/Config.in + +source drivers/parport/Config.in + +source drivers/pnp/Config.in + +source drivers/block/Config.in + +source drivers/md/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +source drivers/telephony/Config.in + +mainmenu_option next_comment +comment 'ATA/IDE/MFM/RLL support' + +tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE + +if [ "$CONFIG_IDE" != "n" ]; then + source drivers/ide/Config.in +else + define_bool CONFIG_BLK_DEV_IDE_MODES n + define_bool CONFIG_BLK_DEV_HD n +fi +endmenu + +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/ieee1394/Config.in + +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_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 + +# +# input before char - char/joystick depends on it. As does USB. +# +source drivers/input/Config.in +source drivers/char/Config.in + +#source drivers/misc/Config.in + +source drivers/media/Config.in + +source fs/Config.in + +source drivers/char/Config.in + +mainmenu_option next_comment +comment 'Sound' + +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source drivers/sound/Config.in +fi +endmenu + +source drivers/usb/Config.in + +mainmenu_option next_comment +comment 'Kernel hacking' + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +bool 'Kernel profiling support' CONFIG_PROFILE +if [ "$CONFIG_PROFILE" = "y" ]; then + int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 +fi +endmenu diff -u --recursive --new-file v2.4.1/linux/arch/cris/cris.ld linux/arch/cris/cris.ld --- v2.4.1/linux/arch/cris/cris.ld Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/cris.ld Tue Feb 13 14:13:43 2001 @@ -0,0 +1,81 @@ +/* ld script to make the Linux/CRIS kernel + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * For now, on Etrax-100 LX, the DRAM starts virtually at 0x6. Normally + * it should be at 0xc. + */ + +SECTIONS +{ + . = 0x60000000; /* DRAM starts virtually at 0x60000000 */ + _dram_start = .; + _ibr_start = .; + . = . + 0x4000; /* see head.S and pages reserved at the start */ + + _text = .; /* Text and read-only data */ + _text_start = .; /* lots of aliases */ + _stext = .; + __stext = .; + .text : { + *(.text) + *(.fixup) + *(.text.__*) + *(.rodata) + } + + . = ALIGN(4); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + _etext = . ; /* End of text section */ + __etext = .; + + . = ALIGN (4); + ___data_rom_start = . ; + ___data_start = . ; + __Sdata = . ; + .data : { /* Data */ + *(.data) + } + __edata = . ; /* End of data section */ + _edata = . ; + + . = ALIGN(8192); /* init_task and stack, must be aligned */ + .data.init_task : { *(.data.init_task) } + + . = ALIGN(8192); /* Init code and data */ + ___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 = .; + __vmlinux_end = .; /* last address of the physical file */ + . = ALIGN(8192); + ___init_end = .; + + __data_end = . ; /* Move to _edata ? */ + __bss_start = .; /* BSS */ + .bss : { + *(COMMON) + *(.bss) + } + + . = ALIGN (0x20); + _end = .; + __end = .; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + + _dram_end = 0x60000000 + @ETRAX_DRAM_SIZE_M@*1024*1024; +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/defconfig linux/arch/cris/defconfig --- v2.4.1/linux/arch/cris/defconfig Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/defconfig Thu Feb 8 16:32:44 2001 @@ -0,0 +1,319 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_UID16=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSVIPC=y +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_JAVA is not set +# CONFIG_KGDB is not set +# CONFIG_ETRAX_WATCHDOG is not set +CONFIG_USE_SERIAL_CONSOLE=y +# CONFIG_KERNEL_IFCONFIG is not set + +# +# Hardware setup +# +CONFIG_ETRAX100LX=y +# CONFIG_SVINTO_SIM is not set +CONFIG_CRIS_LOW_MAP=y +ETRAX_DRAM_BASE=40000000 +ETRAX_DRAM_SIZE=8 +CONFIG_ETRAX_PA_LEDS=y +# CONFIG_ETRAX_PB_LEDS is not set +# CONFIG_ETRAX_90000000_LEDS is not set +# CONFIG_ETRAX_NO_LEDS is not set +CONFIG_ETRAX_LED1G=2 +CONFIG_ETRAX_LED1R=2 +CONFIG_ETRAX_LED2G=2 +CONFIG_ETRAX_LED2R=2 +CONFIG_DEBUG_PORT0=y +# CONFIG_DEBUG_PORT1 is not set +# CONFIG_DEBUG_PORT2 is not set +# CONFIG_DEBUG_PORT3 is not set +DEF_R_WAITSTATES=95a6 +DEF_R_BUS_CONFIG=104 +DEF_R_DRAM_CONFIG=1a200040 +DEF_R_DRAM_TIMING=5611 +DEF_R_PORT_PA_DIR=1d +DEF_R_PORT_PA_DATA=f0 +DEF_R_PORT_PB_CONFIG=00 +DEF_R_PORT_PB_DIR=1e +DEF_R_PORT_PB_DATA=f3 + +# +# Drivers for Etrax built-in interfaces +# +CONFIG_ETRAX_ETHERNET=y +CONFIG_NET_ETHERNET=y +CONFIG_ETRAX_SERIAL=y + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_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 + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI 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_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_CRAMFS=y +CONFIG_RAMFS=y +# 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_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_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_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_NLS is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +# CONFIG_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 + +# +# Input core support is needed for joysticks +# +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Kernel hacking +# +# CONFIG_PROFILE is not set diff -u --recursive --new-file v2.4.1/linux/arch/cris/drivers/Config.in linux/arch/cris/drivers/Config.in --- v2.4.1/linux/arch/cris/drivers/Config.in Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/Config.in Thu Feb 8 16:32:44 2001 @@ -0,0 +1,49 @@ +mainmenu_option next_comment +comment 'Drivers for Etrax built-in interfaces' + +bool 'Ethernet support' CONFIG_ETRAX_ETHERNET y +if [ "$CONFIG_ETRAX_ETHERNET" = "y" ]; then +# this is just so that the user does not have to go into the +# normal ethernet driver section just to enable ethernetworking + define_bool CONFIG_NET_ETHERNET y +fi + +bool 'Serial-port support' CONFIG_ETRAX_SERIAL y + +bool 'ATA/IDE support' CONFIG_ETRAX_IDE n + +if [ "$CONFIG_ETRAX_IDE" = "y" ]; then +# here we should add the CONFIG_'s necessary to enable the basic +# general ide drivers so the common case does not need to go +# into that config submenu. enable disk and CD support. others +# need to go fiddle in the submenu.. + define_bool CONFIG_IDE y + + define_bool CONFIG_BLK_DEV_IDE y + define_bool CONFIG_BLK_DEV_IDEDISK y + define_bool CONFIG_BLK_DEV_IDECD y + + define_bool CONFIG_BLK_DEV_IDEDMA y + define_bool CONFIG_DMA_NONPCI y + + choice 'IDE reset pin' \ + "Port_PB_Bit_7 CONFIG_ETRAX_IDE_PB7_RESET\ + Port_G_Bit_27 CONFIG_ETRAX_IDE_G27_RESET\ + Port_CSE1_Bit_16 CONFIG_ETRAX_IDE_CSE1_16_RESET" Port_PB_Bit_7 +fi + +bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP n + +if [ "$CONFIG_ETRAX_AXISFLASHMAP" = "y" ]; then +# here we define the CONFIG_'s necessary to enable MTD support +# for the flash + define_bool CONFIG_MTD y + + define_bool CONFIG_MTD_CFI y + define_bool CONFIG_MTD_CFI_INTELEXT n + define_bool CONFIG_MTD_CFI_AMDSTD y + + define_bool CONFIG_MTD_CHAR y +fi + +endmenu diff -u --recursive --new-file v2.4.1/linux/arch/cris/drivers/Makefile linux/arch/cris/drivers/Makefile --- v2.4.1/linux/arch/cris/drivers/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/Makefile Thu Feb 8 16:32:44 2001 @@ -0,0 +1,14 @@ +# +# Makefile for Etrax-specific drivers +# + +O_TARGET := drivers.o + +obj-y := + +obj-$(CONFIG_ETRAX_ETHERNET) += ethernet.o +obj-$(CONFIG_ETRAX_SERIAL) += serial.o +obj-$(CONFIG_ETRAX_IDE) += ide.o +obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/cris/drivers/axisflashmap.c linux/arch/cris/drivers/axisflashmap.c --- v2.4.1/linux/arch/cris/drivers/axisflashmap.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/axisflashmap.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,311 @@ +/* + * Physical mapping layer for MTD using the Axis partitiontable format + * + * Copyright (c) 2001 Axis Communications AB + * + * This file is under the GPL. + * + * First partition is always sector 0 regardless of if we find a partitiontable + * or not. In the start of the next sector, there can be a partitiontable that + * tells us what other partitions to define. If there isn't, we use a default + * partition split defined below. + * + * $Log: axisflashmap.c,v $ + * Revision 1.1 2001/01/12 17:01:18 bjornw + * * Added axisflashmap.c, a physical mapping for MTD that reads and understands + * Axis partition-table format. + * + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef CONFIG_CRIS_LOW_MAP +#define FLASH_UNCACHED_ADDR KSEG_E +#define FLASH_CACHED_ADDR KSEG_5 +#else +#define FLASH_UNCACHED_ADDR KSEG_E +#define FLASH_CACHED_ADDR KSEG_F +#endif + +/* + * WINDOW_SIZE is the total size where the flash chips are mapped, + * my guess is that this can be the total memory area even if there + * are many flash chips inside the area or if they are not all mounted. + * So possibly we can get rid of the CONFIG_ here and just write something + * like 32 MB always. + */ + +#define WINDOW_SIZE (CONFIG_ETRAX_FLASH_LENGTH * 1024 * 1024) + +/* Byte-offset where the partition-table is placed in the first chip + */ + +#define PTABLE_SECTOR 65536 + +/* + * Map driver + * + * Ok this is the scoop - we need to access the flash both with and without + * the cache - without when doing all the fancy flash interfacing, and with + * when we do actual copying because otherwise it will be slow like molasses. + * I hope this works the way it's intended, so that there won't be any cases + * of non-synchronicity because of the different access modes below... + */ + +static __u8 flash_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *)(FLASH_UNCACHED_ADDR + ofs); +} + +static __u16 flash_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *)(FLASH_UNCACHED_ADDR + ofs); +} + +static __u32 flash_read32(struct map_info *map, unsigned long ofs) +{ + return *(volatile unsigned int *)(FLASH_UNCACHED_ADDR + ofs); +} + +static void flash_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(FLASH_CACHED_ADDR + from), len); +} + +static void flash_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *(__u8 *)(FLASH_UNCACHED_ADDR + adr) = d; +} + +static void flash_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *)(FLASH_UNCACHED_ADDR + adr) = d; +} + +static void flash_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d; +} + +static void flash_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + memcpy((void *)(FLASH_CACHED_ADDR + to), from, len); +} + +static struct map_info axis_map = { + name: "Axis flash", + size: WINDOW_SIZE, + buswidth: CONFIG_ETRAX_FLASH_BUSWIDTH, + read8: flash_read8, + read16: flash_read16, + read32: flash_read32, + copy_from: flash_copy_from, + write8: flash_write8, + write16: flash_write16, + write32: flash_write32, + copy_to: flash_copy_to +}; + +/* If no partition-table was found, we use this default-set. + */ + +#define MAX_PARTITIONS 7 +#define NUM_DEFAULT_PARTITIONS 3 + +static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { + { + name: "boot firmware", + size: PTABLE_SECTOR, + offset: 0 + }, + { + name: "kernel", + size: 0x1a0000, + offset: PTABLE_SECTOR + }, + { + name: "filesystem", + size: 0x50000, + offset: (0x1a0000 + PTABLE_SECTOR) + } +}; + +static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { + { + name: "part0", + size: 0, + offset: 0 + }, + { + name: "part1", + size: 0, + offset: 0 + }, + { + name: "part2", + size: 0, + offset: 0 + }, + { + name: "part3", + size: 0, + offset: 0 + }, + { + name: "part4", + size: 0, + offset: 0 + }, + { + name: "part5", + size: 0, + offset: 0 + }, + { + name: "part6", + size: 0, + offset: 0 + }, +}; + +/* + * This is the master MTD device for which all the others are just + * auto-relocating aliases. + */ +static struct mtd_info *mymtd; + +/* CFI-scan the flash, and if there was a chip, read the partition-table + * and register the partitions with MTD. + */ + +static int __init +init_axis_flash(void) +{ + int pidx = 0; + struct partitiontable_head *ptable_head; + struct partitiontable_entry *ptable; + int use_default_ptable = 1; /* Until proven otherwise */ + const char *pmsg = " /dev/flash%d at 0x%x, size 0x%x\n"; + + printk(KERN_NOTICE "Axis flash mapping: %x at %x\n", + WINDOW_SIZE, FLASH_CACHED_ADDR); + + mymtd = do_cfi_probe(&axis_map); + + if(!mymtd) { + printk("cfi_probe erred %d\n", mymtd); + return -ENXIO; + } + + mymtd->module = THIS_MODULE; + + /* The partition-table is at an offset within the second + * sector of the flash. We _define_ this to be at offset 64k + * even if the actual sector-size in the flash changes.. for + * now at least. + */ + + ptable_head = FLASH_CACHED_ADDR + PTABLE_SECTOR + PARTITION_TABLE_OFFSET; + pidx++; /* first partition is always set to the default */ + + if ((ptable_head->magic == PARTITION_TABLE_MAGIC) + && (ptable_head->size + < (MAX_PARTITIONS + * sizeof(struct partitiontable_entry) + 4)) + && (*(unsigned long*) + ((void*)ptable_head + + sizeof(*ptable_head) + + ptable_head->size - 4) + == PARTITIONTABLE_END_MARKER)) { + /* Looks like a start, sane length and end of a + * partition table, lets check csum etc. + */ + int ptable_ok = 0; + struct partitiontable_entry *max_addr = + (struct partitiontable_entry *) + ((unsigned long)ptable_head + sizeof(*ptable_head) + + ptable_head->size); + unsigned long offset = PTABLE_SECTOR; + unsigned char *p; + unsigned long csum = 0; + + ptable = (struct partitiontable_entry *) + ((unsigned long)ptable_head + sizeof(*ptable_head)); + + /* Lets be PARANOID, and check the checksum. */ + p = (unsigned char*) ptable; + + while (p <= (unsigned char*)max_addr) { + csum += *p++; + csum += *p++; + csum += *p++; + csum += *p++; + } + /* printk(" total csum: 0x%08X 0x%08X\n", + csum, ptable_head->checksum); */ + ptable_ok = (csum == ptable_head->checksum); + + /* Read the entries and use/show the info. */ + ptable = (struct partitiontable_entry *) + ((unsigned long)ptable_head + sizeof(*ptable_head)); + + printk(" Found %s partition table at 0x%08lX-0x%08lX.\n", + (ptable_ok ? "valid" : "invalid"), + (unsigned long)ptable_head, + (unsigned long)max_addr); + + /* We have found a working bootblock. Now read the + partition table. Scan the table. It ends when + there is 0xffffffff, that is, empty flash. */ + + while (ptable_ok + && ptable->offset != 0xffffffff + && ptable < max_addr + && pidx < MAX_PARTITIONS) { +#if 0 + /* wait with multi-chip support until we know + * how mtd detects multiple chips + */ + if ((offset + ptable->offset) >= chips[0].size) { + partitions[pidx].start + = offset + chips[1].start + + ptable->offset - chips[0].size; + } +#endif + axis_partitions[pidx].offset = offset + ptable->offset; + axis_partitions[pidx].size = ptable->size; + + printk(pmsg, pidx, axis_partitions[pidx].offset, + axis_partitions[pidx].size); + pidx++; + ptable++; + } + use_default_ptable = !ptable_ok; + } + + if(use_default_ptable) { + printk(" Using default partition table\n"); + return add_mtd_partitions(mymtd, axis_default_partitions, + NUM_DEFAULT_PARTITIONS); + } else { + return add_mtd_partitions(mymtd, axis_partitions, pidx); + } +} + +/* This adds the above to the kernels init-call chain */ + +module_init(init_axis_flash); + diff -u --recursive --new-file v2.4.1/linux/arch/cris/drivers/ethernet.c linux/arch/cris/drivers/ethernet.c --- v2.4.1/linux/arch/cris/drivers/ethernet.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/ethernet.c Tue Feb 13 14:13:43 2001 @@ -0,0 +1,1041 @@ +/* $Id: ethernet.c,v 1.5 2000/11/29 17:22:22 bjornw Exp $ + * + * e100net.c: A network driver for the ETRAX 100LX network controller. + * + * Copyright (c) 1998-2000 Axis Communications AB. + * + * The outline of this driver comes from skeleton.c. + * + * $Log: ethernet.c,v $ + * Revision 1.5 2000/11/29 17:22:22 bjornw + * Get rid of the udword types legacy stuff + * + * Revision 1.4 2000/11/22 16:36:09 bjornw + * Please marketing by using the correct case when spelling Etrax. + * + * Revision 1.3 2000/11/21 16:43:04 bjornw + * Minor short->int change + * + * Revision 1.2 2000/11/08 14:27:57 bjornw + * 2.4 port + * + * Revision 1.1 2000/11/06 13:56:00 bjornw + * Verbatim copy of the 1.24 version of e100net.c from elinux + * + * Revision 1.24 2000/10/04 15:55:23 bjornw + * * Use virt_to_phys etc. for DMA addresses + * * Removed bogus CHECKSUM_UNNECESSARY + * + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +//#define ETHDEBUG + +#define D(x) + +/* + * The name of the card. Is used for messages and in the requests for + * io regions, irqs and dma channels + */ + +static const char* cardname = "ETRAX 100LX built-in ethernet controller"; + +/* A default ethernet address. Highlevel SW will set the real one later */ + +static struct sockaddr default_mac = { + 0, + { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 } +}; + +/* Information that need to be kept for each board. */ +struct net_local { + struct net_device_stats stats; + + /* Tx control lock. This protects the transmit buffer ring + * state along with the "tx full" state of the driver. This + * means all netif_queue flow control actions are protected + * by this lock as well. + */ + spinlock_t lock; +}; + +#define NETWORK_DMARX_IRQ 17 /* irq 17 is the DMA1 irq */ +#define NETWORK_DMATX_IRQ 16 /* irq 16 is the DMA0 irq */ +#define NETWORK_STATUS_IRQ 6 /* irq 6 is the network irq */ + +/* Dma descriptors etc. */ + +#define RX_BUF_SIZE 32768 + +#define MAX_MEDIA_DATA_SIZE 1518 + +#define MIN_PACKET_LEN 46 +#define ETHER_HEAD_LEN 14 + +/* +** MDIO constants. +*/ +#define MDIO_BASE_STATUS_REG 0x1 +#define MDIO_BASE_CONTROL_REG 0x0 +#define MDIO_LINK_UP_MASK 0x4 +#define MDIO_START 0x1 +#define MDIO_READ 0x2 +#define MDIO_WRITE 0x1 +#define MDIO_PREAMBLE 0xfffffffful + +/* Broadcom specific */ +#define MDIO_AUX_CTRL_STATUS_REG 0x18 +#define MDIO_SPEED 0x2 +#define MDIO_PHYS_ADDR 0x0 + +/* Network flash constants */ +#define NET_FLASH_TIME 2 /* 20 ms */ +#define NET_LINK_UP_CHECK_INTERVAL 200 /* 2 s */ + +/* RX_DESC_BUF_SIZE should be a multiple of four to avoid the buffer + * alignment bug in Etrax 100 release 1 + */ + +#define RX_DESC_BUF_SIZE 256 +#define NBR_OF_RX_DESC (RX_BUF_SIZE / \ + RX_DESC_BUF_SIZE) + +#define GET_BIT(bit,val) (((val) >> (bit)) & 0x01) + +static etrax_dma_descr *myNextRxDesc; /* Points to the next descriptor to + to be processed */ +static etrax_dma_descr *myLastRxDesc; /* The last processed descriptor */ +static etrax_dma_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */ + +static unsigned char RxBuf[RX_BUF_SIZE]; + +static etrax_dma_descr RxDescList[NBR_OF_RX_DESC]; +static etrax_dma_descr TxDesc; + +static struct sk_buff *tx_skb; + +/* Network speed indication. */ +static struct timer_list speed_timer; +static struct timer_list clear_led_timer; +static int current_speed; +static int led_clear_time; +static int nolink; + +/* Index to functions, as function prototypes. */ + +static int etrax_ethernet_init(struct net_device *dev); + +static int e100_open(struct net_device *dev); +static int e100_set_mac_address(struct net_device *dev, void *addr); +static int e100_send_packet(struct sk_buff *skb, struct net_device *dev); +static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void e100_rx(struct net_device *dev); +static int e100_close(struct net_device *dev); +static struct net_device_stats *e100_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); +static void e100_hardware_send_packet(char *buf, int length); +static void update_rx_stats(struct net_device_stats *); +static void update_tx_stats(struct net_device_stats *); + +static void e100_check_speed(unsigned long dummy); +static unsigned short e100_get_mdio_reg(unsigned char reg_num); +static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd); +static void e100_send_mdio_bit(unsigned char bit); +static unsigned char e100_receive_mdio_bit(void); +static void e100_reset_tranceiver(void); + +static void e100_clear_network_leds(unsigned long dummy); + +#define tx_done(dev) (*R_DMA_CH0_CMD == 0) + +/* + * Check for a network adaptor of this type, and return '0' if one exists. + * If dev->base_addr == 0, probe all likely locations. + * If dev->base_addr == 1, always return failure. + * If dev->base_addr == 2, allocate space for the device and return success + * (detachable devices only). + */ + +static int __init +etrax_ethernet_init(struct net_device *dev) +{ + int i; + int anOffset = 0; + + printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB\n"); + + dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ + + printk("%s initialized\n", dev->name); + + /* make Linux aware of the new hardware */ + + if (!dev) { + printk("dev == NULL. Should this happen?\n"); + dev = init_etherdev(dev, sizeof(struct net_local)); + } + + /* setup generic handlers and stuff in the dev struct */ + + ether_setup(dev); + + /* make room for the local structure containing stats etc */ + + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_local)); + + /* now setup our etrax specific stuff */ + + dev->irq = NETWORK_DMARX_IRQ; /* we really use DMATX as well... */ + dev->dma = 1; + + /* fill in our handlers so the network layer can talk to us in the future */ + + dev->open = e100_open; + dev->hard_start_xmit = e100_send_packet; + dev->stop = e100_close; + dev->get_stats = e100_get_stats; + dev->set_multicast_list = set_multicast_list; + dev->set_mac_address = e100_set_mac_address; + + /* set the default MAC address */ + + e100_set_mac_address(dev, &default_mac); + + /* Initialise the list of Etrax DMA-descriptors */ + + /* Initialise receive descriptors */ + + for(i = 0; i < (NBR_OF_RX_DESC - 1); i++) { + RxDescList[i].ctrl = 0; + RxDescList[i].sw_len = RX_DESC_BUF_SIZE; + RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); + RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); + RxDescList[i].status = 0; + RxDescList[i].hw_len = 0; + anOffset += RX_DESC_BUF_SIZE; + } + + RxDescList[i].ctrl = d_eol; + RxDescList[i].sw_len = RX_DESC_BUF_SIZE; + RxDescList[i].next = virt_to_phys(&RxDescList[0]); + RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); + RxDescList[i].status = 0; + RxDescList[i].hw_len = 0; + + /* Initialise initial pointers */ + + myNextRxDesc = &RxDescList[0]; + myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + + /* Initialize speed indicator stuff. */ + + nolink = 0; + current_speed = 10; + speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; + speed_timer.function = e100_check_speed; + add_timer(&speed_timer); + clear_led_timer.function = e100_clear_network_leds; + clear_led_timer.expires = jiffies + 10; + add_timer(&clear_led_timer); + + return 0; +} + +/* set MAC address of the interface. called from the core after a + * SIOCSIFADDR ioctl, and from the bootup above. + */ + +static int +e100_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + int i; + + /* remember it */ + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* Write it to the hardware. + * Note the way the address is wrapped: + * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24); + * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8); + */ + + *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) | + (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24); + *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8); + *R_NETWORK_SA_2 = 0; + + /* show it in the log as well */ + + printk("%s: changed MAC to ", dev->name); + + for (i = 0; i < 5; i++) + printk("%02X:", dev->dev_addr[i]); + + printk("%02X\n", dev->dev_addr[i]); + + return 0; +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ + +static int +e100_open(struct net_device *dev) +{ + unsigned long flags; + + /* disable the ethernet interface while we configure it */ + + *R_NETWORK_GEN_CONFIG = + IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | + IO_STATE(R_NETWORK_GEN_CONFIG, enable, off); + + /* enable the MDIO output pin */ + + *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable); + + *R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */ + *R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */ + + /* Reset and wait for the DMA channels */ + + RESET_DMA(0); + RESET_DMA(1); + WAIT_DMA(0); + WAIT_DMA(1); + + /* Initialise the etrax network controller */ + + /* allocate the irq corresponding to the receiving DMA */ + + if (request_irq(NETWORK_DMARX_IRQ, e100rx_interrupt, 0, + cardname, (void *)dev)) { + goto grace_exit; + } + + /* allocate the irq corresponding to the transmitting DMA */ + + if (request_irq(NETWORK_DMATX_IRQ, e100tx_interrupt, 0, + cardname, (void *)dev)) { + goto grace_exit; + } + + /* allocate the irq corresponding to the network errors etc */ + + if (request_irq(NETWORK_STATUS_IRQ, e100nw_interrupt, 0, + cardname, (void *)dev)) { + goto grace_exit; + } + + /* + * Always allocate the DMA channels after the IRQ, + * and clean up on failure. + */ + + if(request_dma(0, cardname)) { + goto grace_exit; + } + + if(request_dma(1, cardname)) { + grace_exit: + /* this will cause some 'trying to free free irq' but what the heck... */ + free_dma(0); + free_irq(NETWORK_DMARX_IRQ, NULL); + free_irq(NETWORK_DMATX_IRQ, NULL); + free_irq(NETWORK_STATUS_IRQ, NULL); + return -EAGAIN; + } + + /* give the HW an idea of what MAC address we want */ + + *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) | + (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24); + *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8); + *R_NETWORK_SA_2 = 0; + +#if 0 + /* use promiscuous mode for testing */ + *R_NETWORK_GA_0 = 0xffffffff; + *R_NETWORK_GA_1 = 0xffffffff; + + *R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */ +#else + *R_NETWORK_REC_CONFIG = + IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | + IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable); +#endif + + *R_NETWORK_GEN_CONFIG = + IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | + IO_STATE(R_NETWORK_GEN_CONFIG, enable, on); + + save_flags(flags); + cli(); + + /* enable the irq's for ethernet DMA */ + + *R_IRQ_MASK2_SET = + IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) | + IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); + + *R_IRQ_MASK0_SET = + IO_STATE(R_IRQ_MASK0_SET, overrun, set) | + IO_STATE(R_IRQ_MASK0_SET, underrun, set) | + IO_STATE(R_IRQ_MASK0_SET, excessive_col, set); + + tx_skb = 0; + + /* make sure the irqs are cleared */ + + *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); + *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do); + + /* make sure the rec and transmit error counters are cleared */ + + (void)*R_REC_COUNTERS; /* dummy read */ + (void)*R_TR_COUNTERS; /* dummy read */ + + /* start the receiving DMA channel so we can receive packets from now on */ + + *R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc); + *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start); + + restore_flags(flags); + + /* We are now ready to accept transmit requeusts from + * the queueing layer of the networking. + */ + netif_start_queue(dev); + + return 0; +} + + +static void +e100_check_speed(unsigned long dummy) +{ + unsigned long data; + data = e100_get_mdio_reg(MDIO_BASE_STATUS_REG); + if (!(data & MDIO_LINK_UP_MASK)) { + nolink = 1; + LED_NETWORK_TX_SET(1); /* Make it red, link is down. */ + } else { + nolink = 0; + LED_NETWORK_TX_SET(0); /* Link is up again, clear red LED. */ + data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); + if (data & MDIO_SPEED) { + current_speed = 100; + } else { + current_speed = 10; + } + } + + /* Reinitialize the timer. */ + speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; + add_timer(&speed_timer); +} + +static unsigned short +e100_get_mdio_reg(unsigned char reg_num) +{ + unsigned long flags; + unsigned short cmd; /* Data to be sent on MDIO port */ + unsigned short data; /* Data read from MDIO */ + int bitCounter; + + save_flags(flags); + cli(); + + /* Start of frame, OP Code, Physical Address, Register Address */ + cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (MDIO_PHYS_ADDR << 7) | + (reg_num << 2); + + e100_send_mdio_cmd(cmd, 0); + + data = 0; + + /* Data... */ + for(bitCounter=15; bitCounter>=0 ; bitCounter--) { + data |= (e100_receive_mdio_bit() << bitCounter); + } + + restore_flags(flags); + return data; +} + +static void +e100_send_mdio_cmd(unsigned short cmd, int write_cmd) +{ + int bitCounter; + unsigned char data = 0x2; + + /* Preamble */ + for(bitCounter = 31; bitCounter>= 0; bitCounter--) + e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE)); + + for(bitCounter = 15; bitCounter >= 2; bitCounter--) + e100_send_mdio_bit(GET_BIT(bitCounter, cmd)); + + /* Turnaround */ + for(bitCounter = 1; bitCounter >= 0 ; bitCounter--) + if (write_cmd) + e100_send_mdio_bit(GET_BIT(bitCounter, data)); + else + e100_receive_mdio_bit(); +} + +static void +e100_send_mdio_bit(unsigned char bit) +{ + volatile int i; + *R_NETWORK_MGM_CTRL = 2 | bit&1; + for (i=40; i; i--); + *R_NETWORK_MGM_CTRL = 6 | bit&1; + for (i=40; i; i--); +} + +static unsigned char +e100_receive_mdio_bit() +{ + unsigned char bit; + volatile int i; + *R_NETWORK_MGM_CTRL = 0; + bit = *R_NETWORK_STAT & 1; + for (i=40; i; i--); + *R_NETWORK_MGM_CTRL = 4; + for (i=40; i; i--); + return bit; +} + +static void +e100_reset_tranceiver(void) +{ + unsigned long flags; + unsigned short cmd; + unsigned short data; + int bitCounter; + + save_flags(flags); + cli(); + + data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG); + + cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | (MDIO_BASE_CONTROL_REG << 2); + + e100_send_mdio_cmd(cmd, 0); + + data |= 0x8000; + + for(bitCounter = 15; bitCounter >= 0 ; bitCounter--) { + e100_send_mdio_bit(GET_BIT(bitCounter, data)); + } + + restore_flags(flags); +} + +/* Called by upper layers if they decide it took too long to complete + * sending a packet - we need to reset and stuff. + */ + +static void +e100_tx_timeout(struct net_device *dev) +{ + struct net_local *np = (struct net_local *)dev->priv; + + printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, + tx_done(dev) ? "IRQ problem" : "network cable problem"); + + /* remember we got an error */ + + np->stats.tx_errors++; + + /* reset the TX DMA in case it has hung on something */ + + RESET_DMA(0); + WAIT_DMA(0); + + /* Reset the tranceiver. */ + + e100_reset_tranceiver(); + + /* and get rid of the packet that never got an interrupt */ + + dev_kfree_skb(tx_skb); + tx_skb = 0; + + /* tell the upper layers we're ok again */ + + netif_wake_queue(dev); +} + + +/* This will only be invoked if the driver is _not_ in XOFF state. + * What this means is that we need not check it, and that this + * invariant will hold if we make sure that the netif_*_queue() + * calls are done at the proper times. + */ + +static int +e100_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *np = (struct net_local *)dev->priv; + int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = skb->data; + +#ifdef ETHDEBUG + printk("send packet len %d\n", length); +#endif + spin_lock_irq(&np->lock); /* protect from tx_interrupt */ + + tx_skb = skb; /* remember it so we can free it in the tx irq handler later */ + dev->trans_start = jiffies; + + e100_hardware_send_packet(buf, length); + + /* this simple TX driver has only one send-descriptor so we're full + * directly. If this had a send-ring instead, we would only do this if + * the ring got full. + */ + + netif_stop_queue(dev); + + spin_unlock_irq(&np->lock); + + return 0; +} + +/* + * The typical workload of the driver: + * Handle the network interface interrupts. + */ + +static void +e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + unsigned long irqbits = *R_IRQ_MASK2_RD; + + if(irqbits & (1U << 3)) { + + /* acknowledge the eop interrupt */ + + *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do); + + /* check if one or more complete packets were indeed received */ + + while(*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) { + /* Take out the buffer and give it to the OS, then + * allocate a new buffer to put a packet in. + */ + e100_rx(dev); + ((struct net_local *)dev->priv)->stats.rx_packets++; + *R_DMA_CH1_CMD = 3; /* restart/continue on the channel, for safety */ + *R_DMA_CH1_CLR_INTR = 3; /* clear dma channel 1 eop/descr irq bits */ + /* now, we might have gotten another packet so we have to loop back + and check if so */ + } + } +} + +/* the transmit dma channel interrupt + * + * this is supposed to free the skbuff which was pending during transmission, + * and inform the kernel that we can send one more buffer + */ + +static void +e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + unsigned long irqbits = *R_IRQ_MASK2_RD; + struct net_local *np = (struct net_local *)dev->priv; + + if(irqbits & 2) { /* check for a dma0_eop interrupt */ + + /* This protects us from concurrent execution of + * our dev->hard_start_xmit function above. + */ + + spin_lock(&np->lock); + + /* acknowledge the eop interrupt */ + + *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); + + if(*R_DMA_CH0_FIRST == 0 && tx_skb) { + np->stats.tx_bytes += tx_skb->len; + np->stats.tx_packets++; + /* dma is ready with the transmission of the data in tx_skb, so now + we can release the skb memory */ + dev_kfree_skb_irq(tx_skb); + tx_skb = 0; + netif_wake_queue(dev); + } else { + printk("tx weird interrupt\n"); + } + + spin_unlock(&np->lock); + } +} + +static void +e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = (struct net_device *)dev_id; + struct net_local *np = (struct net_local *)dev->priv; + unsigned long irqbits = *R_IRQ_MASK0_RD; + + if(irqbits & (1 << 19)) { /* check for overrun irq */ + update_rx_stats(&np->stats); /* this will ack the irq */ + D(printk("ethernet receiver overrun!\n")); + } + if(irqbits & (1 << 17)) { /* check for excessive collision irq */ + *R_NETWORK_TR_CTRL = 1 << 8; /* clear the interrupt */ + np->stats.tx_errors++; + D(printk("ethernet excessive collisions!\n")); + } + +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void +e100_rx(struct net_device *dev) +{ + struct sk_buff *skb; + int length=0; + int i; + struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; + unsigned char *skb_data_ptr; + + /* light the network rx packet depending on the current speed. + ** But only if link has been detected. + */ + if (!nolink) + if (current_speed == 10) { + LED_NETWORK_TX_SET(1); + LED_NETWORK_RX_SET(1); + } else + LED_NETWORK_RX_SET(1); + + /* Set the earliest time we may clear the LED */ + + led_clear_time = jiffies + NET_FLASH_TIME; + + /* If the packet is broken down in many small packages then merge + * count how much space we will need to alloc with skb_alloc() for + * it to fit. + */ + + while (!(myNextRxDesc->status & d_eop)) { + length += myNextRxDesc->sw_len; /* use sw_len for the first descs */ + myNextRxDesc->status = 0; + myNextRxDesc = phys_to_virt(myNextRxDesc->next); + } + + length += myNextRxDesc->hw_len; /* use hw_len for the last descr */ + +#ifdef ETHDEBUG + printk("Got a packet of length %d:\n", length); + /* dump the first bytes in the packet */ + skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf); + for(i = 0; i < 8; i++) { + printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, + skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3], + skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]); + skb_data_ptr += 8; + } +#endif + + skb = dev_alloc_skb(length - ETHER_HEAD_LEN); + if (!skb) { + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", + dev->name); + return; + } + + skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ + skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ + +#if 0 + printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", + skb->head, skb->data, skb->tail, skb->end); + printk("copying packet to 0x%x.\n", skb_data_ptr); +#endif + + /* this loop can be made using max two memcpy's if optimized */ + + while(mySaveRxDesc != myNextRxDesc) { + memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), + mySaveRxDesc->sw_len); + skb_data_ptr += mySaveRxDesc->sw_len; + mySaveRxDesc = phys_to_virt(mySaveRxDesc->next); + } + + memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), + mySaveRxDesc->hw_len); + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + + /* Send the packet to the upper layers */ + + netif_rx(skb); + + /* Prepare for next packet */ + + myNextRxDesc->status = 0; + myPrevRxDesc = myNextRxDesc; + myNextRxDesc = phys_to_virt(myNextRxDesc->next); + + myPrevRxDesc->ctrl |= d_eol; + myLastRxDesc->ctrl &= ~d_eol; + myLastRxDesc = myPrevRxDesc; + + return; +} + +/* The inverse routine to net_open(). */ +static int +e100_close(struct net_device *dev) +{ + struct net_local *np = (struct net_local *)dev->priv; + + printk("Closing %s.\n", dev->name); + + netif_stop_queue(dev); + + *R_NETWORK_GEN_CONFIG = + IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | + IO_STATE(R_NETWORK_GEN_CONFIG, enable, off); + + *R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */ + *R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */ + + /* Stop the receiver and the transmitter */ + + RESET_DMA(0); + RESET_DMA(1); + + /* Flush the Tx and disable Rx here. */ + + free_irq(NETWORK_DMARX_IRQ, NULL); + free_irq(NETWORK_DMATX_IRQ, NULL); + free_irq(NETWORK_STATUS_IRQ, NULL); + + free_dma(0); + free_dma(1); + + /* Update the statistics here. */ + + update_rx_stats(&np->stats); + update_tx_stats(&np->stats); + + return 0; +} + +static void +update_rx_stats(struct net_device_stats *es) +{ + unsigned long r = *R_REC_COUNTERS; + /* update stats relevant to reception errors */ + es->rx_fifo_errors += r >> 24; /* fifo overrun */ + es->rx_crc_errors += r & 0xff; /* crc error */ + es->rx_frame_errors += (r >> 8) & 0xff; /* alignment error */ + es->rx_length_errors += (r >> 16) & 0xff; /* oversized frames */ +} + +static void +update_tx_stats(struct net_device_stats *es) +{ + unsigned long r = *R_TR_COUNTERS; + /* update stats relevant to transmission errors */ + es->collisions += (r & 0xff) + ((r >> 8) & 0xff); /* single_col + multiple_col */ + es->tx_errors += (r >> 24) & 0xff; /* deferred transmit frames */ +} + +/* + * Get the current statistics. + * This may be called with the card open or closed. + */ +static struct net_device_stats * +e100_get_stats(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + update_rx_stats(&lp->stats); + update_tx_stats(&lp->stats); + + return &lp->stats; +} + +/* + * Set or clear the multicast filter for this adaptor. + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets, + * and do best-effort filtering. + */ +static void +set_multicast_list(struct net_device *dev) +{ + int num_addr = dev->mc_count; + unsigned long int lo_bits; + unsigned long int hi_bits; + if (num_addr == -1) + { + /* promiscuous mode */ + lo_bits = 0xfffffffful; + hi_bits = 0xfffffffful; + } else if (num_addr == 0) { + /* Normal, clear the mc list */ + lo_bits = 0x00000000ul; + hi_bits = 0x00000000ul; + } else { + /* MC mode, receive normal and MC packets */ + char hash_ix; + struct dev_mc_list *dmi = dev->mc_list; + int i; + char *baddr; + lo_bits = 0x00000000ul; + hi_bits = 0x00000000ul; + for (i=0; idmi_addr; + hash_ix ^= (*baddr) & 0x3f; + hash_ix ^= ((*baddr) >> 6) & 0x03; + ++baddr; + hash_ix ^= ((*baddr) << 2) & 0x03c; + hash_ix ^= ((*baddr) >> 4) & 0xf; + ++baddr; + hash_ix ^= ((*baddr) << 4) & 0x30; + hash_ix ^= ((*baddr) >> 2) & 0x3f; + ++baddr; + hash_ix ^= (*baddr) & 0x3f; + hash_ix ^= ((*baddr) >> 6) & 0x03; + ++baddr; + hash_ix ^= ((*baddr) << 2) & 0x03c; + hash_ix ^= ((*baddr) >> 4) & 0xf; + ++baddr; + hash_ix ^= ((*baddr) << 4) & 0x30; + hash_ix ^= ((*baddr) >> 2) & 0x3f; + + hash_ix &= 0x3f; + + if (hash_ix > 32) { + hi_bits |= (1 << (hash_ix-32)); + } + else { + lo_bits |= (1 << hash_ix); + } + dmi = dmi->next; + } + } + *R_NETWORK_GA_0 = lo_bits; + *R_NETWORK_GA_1 = hi_bits; +} + +void +e100_hardware_send_packet(char *buf, int length) +{ + D(printk("e100 send pack, buf 0x%x len %d\n", buf, length)); + /* light the network leds depending on the current speed. + ** But only if link has been detected. + */ + if (!nolink) { + if (current_speed == 10) { + LED_NETWORK_TX_SET(1); + LED_NETWORK_RX_SET(1); + } else { + LED_NETWORK_RX_SET(1); + } + } + + /* Set the earliest time we may clear the LED */ + + led_clear_time = jiffies + NET_FLASH_TIME; + + /* configure the tx dma descriptor */ + + TxDesc.sw_len = length; + TxDesc.ctrl = d_eop | d_eol | d_wait; + TxDesc.buf = virt_to_phys(buf); + + /* setup the dma channel and start it */ + + *R_DMA_CH0_FIRST = virt_to_phys(&TxDesc); + *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, start); +} + +static void +e100_clear_network_leds(unsigned long dummy) +{ + if (jiffies > led_clear_time) { + if (nolink) + LED_NETWORK_TX_SET(1); + else + LED_NETWORK_TX_SET(0); + LED_NETWORK_RX_SET(0); + } + + clear_led_timer.expires = jiffies + 10; + add_timer(&clear_led_timer); +} + +static struct net_device dev_etrax_ethernet; /* only got one */ + +static int +etrax_init_module(void) +{ + struct net_device *d = &dev_etrax_ethernet; + + d->init = etrax_ethernet_init; + + if(register_netdev(d) == 0) + return 0; + else + return -ENODEV; +} + +module_init(etrax_init_module); diff -u --recursive --new-file v2.4.1/linux/arch/cris/drivers/ide.c linux/arch/cris/drivers/ide.c --- v2.4.1/linux/arch/cris/drivers/ide.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/ide.c Tue Feb 13 14:13:43 2001 @@ -0,0 +1,818 @@ +/* $Id: ide.c,v 1.4 2001/01/10 21:14:32 bjornw Exp $ + * + * Etrax specific IDE functions, like init and PIO-mode setting etc. + * Almost the entire ide.c is used for the rest of the Etrax ATA driver. + * Copyright (c) 2000, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen (initial version) + * Mikael Starvik (pio setup stuff) + * + * $Log: ide.c,v $ + * Revision 1.4 2001/01/10 21:14:32 bjornw + * Initialize hwif->ideproc, for the new way of handling ide_xxx_data + * + * Revision 1.3 2000/12/01 17:48:18 bjornw + * - atapi_output_bytes now uses DMA + * - dma_active check removed - the kernel does proper serializing and it had + * a race-condition anyway + * - ide_build_dmatable had a nameclash + * - re-added the RESET_DMA thingys because sometimes the interface can get + * stuck apparently + * - added ide_release_dma + * + * Revision 1.2 2000/11/29 17:31:29 bjornw + * 2.4 port + * + * - The "register addresses" stored in the hwif are now 32-bit fields that + * don't need to be shifted into correct positions in R_ATA_CTRL_DATA + * - PIO-mode detection temporarily disabled since ide-modes.c is not compiled + * - All DMA uses virt_to_phys conversions for DMA buffers and descriptor ptrs + * - Probably correct ide_dma_begin semantics in dmaproc now for ATAPI devices + * - Removed RESET_DMA when starting a new transfer - why was this necessary ? + * - Indentation fix + * + * + */ + +/* Regarding DMA: + * + * There are two forms of DMA - "DMA handshaking" between the interface and the drive, + * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's + * something built-in in the Etrax. However only some drives support the DMA-mode handshaking + * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the + * device can't do DMA handshaking for some stupid reason. We don't need to do that. + */ + +#undef REALLY_SLOW_IO /* most systems can safely undef this */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* number of Etrax DMA descriptors */ +#define MAX_DMA_DESCRS 64 + +#define LOWDB(x) +#define D(x) + +void OUT_BYTE(unsigned char data, ide_ioreg_t reg) { + LOWDB(printk("ob: data 0x%x, reg 0x%x\n", data, reg)); + while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */ + *R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */ + while(!(*R_ATA_STATUS_DATA & + IO_MASK(R_ATA_STATUS_DATA, tr_rdy))); /* wait for transmitter ready */ +} + +unsigned char IN_BYTE(ide_ioreg_t reg) { + int status; + while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */ + *R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */ + while(!((status = *R_ATA_STATUS_DATA) & + IO_MASK(R_ATA_STATUS_DATA, dav))); /* wait for available */ + LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg)); + return (unsigned char)status; /* data was in the lower 16 bits in the status reg */ +} + +/* PIO timing (in R_ATA_CONFIG) + * + * _____________________________ + * ADDRESS : ________/ + * + * _______________ + * DIOR : ____________/ \__________ + * + * _______________ + * DATA : XXXXXXXXXXXXXXXX_______________XXXXXXXX + * + * + * DIOR is unbuffered while address and data is buffered. + * This creates two problems: + * 1. The DIOR pulse is to early (because it is unbuffered) + * 2. The rise time of DIOR is long + * + * There are at least three different plausible solutions + * 1. Use a pad capable of larger currents in Etrax + * 2. Use an external buffer + * 3. Make the strobe pulse longer + * + * Some of the strobe timings below are modified to compensate + * for this. This implies a slight performance decrease. + * + * THIS SHOULD NEVER BE CHANGED! + * + * TODO: Is this true for the latest LX boards still ? + */ + +#define ATA_DMA2_STROBE 4 +#define ATA_DMA2_HOLD 0 +#define ATA_DMA1_STROBE 4 +#define ATA_DMA1_HOLD 1 +#define ATA_DMA0_STROBE 12 +#define ATA_DMA0_HOLD 9 +#define ATA_PIO4_SETUP 1 +#define ATA_PIO4_STROBE 5 +#define ATA_PIO4_HOLD 0 +#define ATA_PIO3_SETUP 1 +#define ATA_PIO3_STROBE 5 +#define ATA_PIO3_HOLD 1 +#define ATA_PIO2_SETUP 1 +#define ATA_PIO2_STROBE 6 +#define ATA_PIO2_HOLD 2 +#define ATA_PIO1_SETUP 2 +#define ATA_PIO1_STROBE 11 +#define ATA_PIO1_HOLD 4 +#define ATA_PIO0_SETUP 4 +#define ATA_PIO0_STROBE 19 +#define ATA_PIO0_HOLD 4 + +/* + * good_dma_drives() lists the model names (from "hdparm -i") + * of drives which do not support mword2 DMA but which are + * known to work fine with this interface under Linux. + */ + +const char *good_dma_drives[] = {"Micropolis 2112A", + "CONNER CTMA 4000", + "CONNER CTT8000-A", + NULL}; + +static void tune_e100_ide(ide_drive_t *drive, byte pio) +{ + unsigned long flags; + + pio = 4; + //pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + + save_flags(flags); + cli(); + + /* set pio mode! */ + + switch(pio) { + case 0: + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO0_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO0_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO0_HOLD ) ); + break; + case 1: + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO1_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO1_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO1_HOLD ) ); + break; + case 2: + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO2_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO2_HOLD ) ); + break; + case 3: + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO3_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO3_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO3_HOLD ) ); + break; + case 4: + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) ); + break; + } + restore_flags(flags); +} + +static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive); /* defined below */ +static void e100_ideproc (ide_ide_action_t func, ide_drive_t *drive, + void *buffer, unsigned int length); /* defined below */ + +void __init init_e100_ide (void) +{ + volatile unsigned int dummy; + int h; + + printk("ide: ETRAX 100LX built-in ATA DMA controller\n"); + + /* first fill in some stuff in the ide_hwifs fields */ + + for(h = 0; h < MAX_HWIFS; h++) { + ide_hwif_t *hwif = &ide_hwifs[h]; + hwif->chipset = ide_etrax100; + hwif->tuneproc = &tune_e100_ide; + hwif->dmaproc = &e100_dmaproc; + hwif->ideproc = &e100_ideproc; + } + /* actually reset and configure the etrax100 ide/ata interface */ + + /* de-assert bus-reset */ +#ifdef CONFIG_ETRAX_IDE_PB7_RESET + port_pb_dir_shadow = port_pb_dir_shadow | + IO_STATE(R_PORT_PB_DIR, dir7, output); + *R_PORT_PB_DIR = port_pb_dir_shadow; + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1); +#endif +#ifdef CONFIG_ETRAX_IDE_G27_RESET + *R_PORT_G_DATA = 0; +#endif + + *R_ATA_CTRL_DATA = 0; + *R_ATA_TRANSFER_CNT = 0; + *R_ATA_CONFIG = 0; + + genconfig_shadow = (genconfig_shadow & + ~IO_MASK(R_GEN_CONFIG, dma2) & + ~IO_MASK(R_GEN_CONFIG, dma3) & + ~IO_MASK(R_GEN_CONFIG, ata)) | + ( IO_STATE( R_GEN_CONFIG, dma3, ata ) | + IO_STATE( R_GEN_CONFIG, dma2, ata ) | + IO_STATE( R_GEN_CONFIG, ata, select ) ); + + *R_GEN_CONFIG = genconfig_shadow; + +#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET + *(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 0; +#endif + + /* wait some */ + + dummy = 1; + dummy = 2; + dummy = 3; + +#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET + *(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 1 << 16; + *R_PORT_G_DATA = 0; /* de-assert bus-reset */ +#endif + + /* make a dummy read to set the ata controller in a proper state */ + dummy = *R_ATA_STATUS_DATA; + + *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) | + IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) | + IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) | + IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) | + IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) | + IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) ); + + *R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw, read) | + IO_FIELD( R_ATA_CTRL_DATA, addr, 1 ) ); + + while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/ + + *R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) | + IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) | + IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) | + IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) ); + + printk("ide: waiting 10 seconds for drives to regain consciousness\n"); + + h = jiffies + 1000; + while(jiffies < h) ; + + /* reset the dma channels we will use */ + + RESET_DMA(2); + RESET_DMA(3); + WAIT_DMA(2); + WAIT_DMA(3); + +} + +static etrax_dma_descr mydescr; + +/* + * The following routines are mainly used by the ATAPI drivers. + * + * These routines will round up any request for an odd number of bytes, + * so if an odd bytecount is specified, be sure that there's at least one + * extra byte allocated for the buffer. + */ +static void +e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) +{ + ide_ioreg_t data_reg = IDE_DATA_REG; + unsigned long status; + + D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n", + data_reg, buffer, bytecount)); + + if(bytecount & 1) { + printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount); + bytecount++; /* to round off */ + } + + /* make sure the DMA channel is available */ + RESET_DMA(3); + WAIT_DMA(3); + + /* setup DMA descriptor */ + + mydescr.sw_len = bytecount; + mydescr.ctrl = d_eol; + mydescr.buf = virt_to_phys(buffer); + + /* start the dma channel */ + + *R_DMA_CH3_FIRST = virt_to_phys(&mydescr); + *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); + + /* initiate a multi word dma read using PIO handshaking */ + + *R_ATA_TRANSFER_CNT = bytecount >> 1; + + *R_ATA_CTRL_DATA = data_reg | + IO_STATE(R_ATA_CTRL_DATA, rw, read) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | + IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + /* wait for completion */ + + LED_DISK_READ(1); + WAIT_DMA(3); + LED_DISK_READ(0); + +#if 0 + /* old polled transfer code */ + + /* initiate a multi word read */ + + *R_ATA_TRANSFER_CNT = wcount << 1; + + *R_ATA_CTRL_DATA = data_reg | + IO_STATE(R_ATA_CTRL_DATA, rw, read) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, register) | + IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + /* svinto has a latency until the busy bit actually is set */ + + nop(); nop(); + nop(); nop(); + nop(); nop(); + nop(); nop(); + nop(); nop(); + + /* unit should be busy during multi transfer */ + while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) { + while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav))) + status = *R_ATA_STATUS_DATA; + *ptr++ = (unsigned short)(status & 0xffff); + } +#endif +} + +static void +e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount) +{ + ide_ioreg_t data_reg = IDE_DATA_REG; + unsigned short *ptr = (unsigned short *)buffer; + unsigned long ctrl; + + D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n", + data_reg, buffer, bytecount)); + + if(bytecount & 1) { + printk("odd bytecount %d in atapi_out_bytes!\n", bytecount); + bytecount++; + } + + /* make sure the DMA channel is available */ + RESET_DMA(2); + WAIT_DMA(2); + + /* setup DMA descriptor */ + + mydescr.sw_len = bytecount; + mydescr.ctrl = d_eol; + mydescr.buf = virt_to_phys(buffer); + + /* start the dma channel */ + + *R_DMA_CH2_FIRST = virt_to_phys(&mydescr); + *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start); + + /* initiate a multi word dma write using PIO handshaking */ + + *R_ATA_TRANSFER_CNT = bytecount >> 1; + + *R_ATA_CTRL_DATA = data_reg | + IO_STATE(R_ATA_CTRL_DATA, rw, write) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | + IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + /* wait for completion */ + + LED_DISK_WRITE(1); + WAIT_DMA(2); + LED_DISK_WRITE(0); + +#if 0 + /* old polled write code */ + + while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */ + + /* initiate a multi word write */ + + *R_ATA_TRANSFER_CNT = bytecount >> 1; + + ctrl = data_reg | + IO_STATE(R_ATA_CTRL_DATA, rw, write) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, register) | + IO_STATE(R_ATA_CTRL_DATA, handsh, pio) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + LED_DISK_WRITE(1); + + /* Etrax will set busy = 1 until the multi pio transfer has finished + * and tr_rdy = 1 after each succesful word transfer. + * When the last byte has been transferred Etrax will first set tr_tdy = 1 + * and then busy = 0 (not in the same cycle). If we read busy before it + * has been set to 0 we will think that we should transfer more bytes + * and then tr_rdy would be 0 forever. This is solved by checking busy + * in the inner loop. + */ + + do { + *R_ATA_CTRL_DATA = ctrl | *ptr++; + while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) && + (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy))); + } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); + + LED_DISK_WRITE(0); +#endif +} + +/* + * This is used for most PIO data transfers *from* the IDE interface + */ +static void +e100_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +{ + e100_atapi_input_bytes(drive, buffer, wcount << 2); +} + +/* + * This is used for most PIO data transfers *to* the IDE interface + */ +static void +e100_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) +{ + e100_atapi_output_bytes(drive, buffer, wcount << 2); +} + +/* + * The multiplexor for ide_xxxput_data and atapi calls + */ +static void +e100_ideproc (ide_ide_action_t func, ide_drive_t *drive, + void *buffer, unsigned int length) +{ + switch (func) { + case ideproc_ide_input_data: + e100_ide_input_data(drive, buffer, length); + break; + case ideproc_ide_output_data: + e100_ide_input_data(drive, buffer, length); + break; + case ideproc_atapi_input_bytes: + e100_atapi_input_bytes(drive, buffer, length); + break; + case ideproc_atapi_output_bytes: + e100_atapi_output_bytes(drive, buffer, length); + break; + default: + printk("e100_ideproc: unsupported func %d!\n", func); + break; + } +} + +/* we only have one DMA channel on the chip for ATA, so we can keep these statically */ +static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS]; +static unsigned int ata_tot_size; + +/* + * e100_ide_build_dmatable() prepares a dma request. + * Returns 0 if all went okay, returns 1 otherwise. + */ +static int e100_ide_build_dmatable (ide_drive_t *drive) +{ + struct request *rq = HWGROUP(drive)->rq; + struct buffer_head *bh = rq->bh; + unsigned long size, addr; + unsigned int count = 0; + + ata_tot_size = 0; + + do { + /* + * Determine addr and size of next buffer area. We assume that + * individual virtual buffers are always composed linearly in + * physical memory. For example, we assume that any 8kB buffer + * is always composed of two adjacent physical 4kB pages rather + * than two possibly non-adjacent physical 4kB pages. + */ + if (bh == NULL) { /* paging and tape requests have (rq->bh == NULL) */ + addr = virt_to_phys (rq->buffer); + size = rq->nr_sectors << 9; + } else { + /* group sequential buffers into one large buffer */ + addr = virt_to_phys (bh->b_data); + size = bh->b_size; + while ((bh = bh->b_reqnext) != NULL) { + if ((addr + size) != virt_to_phys (bh->b_data)) + break; + size += bh->b_size; + } + } + + /* did we run out of descriptors? */ + + if(count >= MAX_DMA_DESCRS) { + printk("%s: too few DMA descriptors\n", drive->name); + return 1; + } + + /* uh.. I'm lazy.. if size >= 65536, it should loop below and split it in + more than one descriptor */ + + if(size >= 65536) { + printk("too large ATA DMA request block, size = %d!\n", size); + return 1; + } + + /* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more + than 65536 words per transfer, so in that case we need to either + 1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with + the descriptors, or + 2) simply do the request here, and get dma_intr to only ide_end_request on + those blocks that were actually set-up for transfer. + */ + + if(ata_tot_size + size >= 131072) { + printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, size); + return 1; + } + + /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */ + + ata_descrs[count].sw_len = size; + ata_descrs[count].ctrl = 0; + ata_descrs[count].buf = addr; + ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]); + count++; + ata_tot_size += size; + + } while (bh != NULL); + + if (count) { + /* set the end-of-list flag on the last descriptor */ + ata_descrs[count - 1].ctrl |= d_eol; + /* return and say all is ok */ + return 0; + } + + printk("%s: empty DMA table?\n", drive->name); + return 1; /* let the PIO routines handle this weirdness */ +} + +static int config_drive_for_dma (ide_drive_t *drive) +{ + const char **list; + struct hd_driveid *id = drive->id; + + if (id && (id->capability & 1)) { + /* Enable DMA on any drive that supports mword2 DMA */ + if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) { + drive->using_dma = 1; + return 0; /* DMA enabled */ + } + + /* Consult the list of known "good" drives */ + list = good_dma_drives; + while (*list) { + if (!strcmp(*list++,id->model)) { + drive->using_dma = 1; + return 0; /* DMA enabled */ + } + } + } + return 1; /* DMA not enabled */ +} + +/* + * etrax_dma_intr() is the handler for disk read/write DMA interrupts + */ +static ide_startstop_t etrax_dma_intr (ide_drive_t *drive) +{ + int i, dma_stat; + byte stat; + + LED_DISK_READ(0); + LED_DISK_WRITE(0); + + dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive); + stat = GET_STAT(); /* get drive status */ + if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { + if (!dma_stat) { + struct request *rq; + rq = HWGROUP(drive)->rq; + for (i = rq->nr_sectors; i > 0;) { + i -= rq->current_nr_sectors; + ide_end_request(1, HWGROUP(drive)); + } + return ide_stopped; + } + printk("%s: bad DMA status\n", drive->name); + } + return ide_error(drive, "dma_intr", stat); +} + +/* + * e100_dmaproc() initiates/aborts DMA read/write operations on a drive. + * + * The caller is assumed to have selected the drive and programmed the drive's + * sector address using CHS or LBA. All that remains is to prepare for DMA + * and then issue the actual read/write DMA/PIO command to the drive. + * + * For ATAPI devices, we just prepare for DMA and return. The caller should + * then issue the packet command to the drive and call us again with + * ide_dma_begin afterwards. + * + * Returns 0 if all went well. + * Returns 1 if DMA read/write could not be started, in which case + * the caller should revert to PIO for the current request. + */ + +static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive) +{ + static unsigned int reading; /* static to support ide_dma_begin semantics */ + int atapi = 0; + + D(printk("e100_dmaproc func %d\n", func)); + + switch (func) { + case ide_dma_verbose: + return 0; + case ide_dma_check: + return config_drive_for_dma (drive); + case ide_dma_off: + case ide_dma_off_quietly: + /* ok.. we don't really need to do anything I think. */ + return 0; + case ide_dma_write: + reading = 0; + break; + case ide_dma_read: + reading = 1; + break; + case ide_dma_begin: + /* begin DMA, used by ATAPI devices which want to issue the + * appropriate IDE command themselves. + * + * they have already called ide_dma_read/write to set the + * static reading flag, now they call ide_dma_begin to do + * the real stuff. we tell our code below not to issue + * any IDE commands itself and jump into it. + */ + atapi++; + goto dma_begin; + case ide_dma_end: /* returns 1 on error, 0 otherwise */ + /* TODO: check if something went wrong with the DMA */ + return 0; + + default: + printk("e100_dmaproc: unsupported func %d\n", func); + return 1; + } + + /* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction + * then they call ide_dma_begin after they have issued the appropriate drive command + * themselves to actually start the chipset DMA. so we just return here if we're + * not a diskdrive. + */ + + if (drive->media != ide_disk) + return 0; + + dma_begin: + + if(reading) { + + RESET_DMA(3); /* sometimes the DMA channel get stuck so we need to do this */ + WAIT_DMA(3); + + /* set up the Etrax DMA descriptors */ + + if(e100_ide_build_dmatable (drive)) + return 1; + + if(!atapi) { + /* set the irq handler which will finish the request when DMA is done */ + + ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL); + + /* issue cmd to drive */ + + OUT_BYTE(WIN_READDMA, IDE_COMMAND_REG); + } + + /* begin DMA */ + + *R_DMA_CH3_FIRST = virt_to_phys(ata_descrs); + *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); + + /* initiate a multi word dma read using DMA handshaking */ + + *R_ATA_TRANSFER_CNT = ata_tot_size >> 1; + + *R_ATA_CTRL_DATA = IDE_DATA_REG | + IO_STATE(R_ATA_CTRL_DATA, rw, read) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | + IO_STATE(R_ATA_CTRL_DATA, handsh, dma) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + LED_DISK_READ(1); + + D(printk("dma read of %d bytes.\n", ata_tot_size)); + + } else { + /* writing */ + + RESET_DMA(2); /* sometimes the DMA channel get stuck so we need to do this */ + WAIT_DMA(2); + + /* set up the Etrax DMA descriptors */ + + if(e100_ide_build_dmatable (drive)) + return 1; + + if(!atapi) { + /* set the irq handler which will finish the request when DMA is done */ + + ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL); + + /* issue cmd to drive */ + + OUT_BYTE(WIN_WRITEDMA, IDE_COMMAND_REG); + } + + /* begin DMA */ + + *R_DMA_CH2_FIRST = virt_to_phys(ata_descrs); + *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start); + + /* initiate a multi word dma write using DMA handshaking */ + + *R_ATA_TRANSFER_CNT = ata_tot_size >> 1; + + *R_ATA_CTRL_DATA = IDE_DATA_REG | + IO_STATE(R_ATA_CTRL_DATA, rw, write) | + IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) | + IO_STATE(R_ATA_CTRL_DATA, handsh, dma) | + IO_STATE(R_ATA_CTRL_DATA, multi, on) | + IO_STATE(R_ATA_CTRL_DATA, dma_size, word); + + LED_DISK_WRITE(1); + + D(printk("dma write of %d bytes.\n", ata_tot_size)); + } + + /* DMA started successfully */ + return 0; +} + +/* ide.c calls this, but we don't need to do anything particular */ + +int ide_release_dma (ide_hwif_t *hwif) +{ + return 1; +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c --- v2.4.1/linux/arch/cris/drivers/serial.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/serial.c Tue Feb 13 14:13:43 2001 @@ -0,0 +1,3039 @@ +/* $Id: serial.c,v 1.6 2000/11/22 16:36:09 bjornw Exp $ + * + * Serial port driver for the ETRAX 100LX chip + * + * Copyright (C) 1998, 1999, 2000 Axis Communications AB + * + * Many, many authors. Based once upon a time on serial.c for 16x50. + * + * $Log: serial.c,v $ + * Revision 1.6 2000/11/22 16:36:09 bjornw + * Please marketing by using the correct case when spelling Etrax. + * + * Revision 1.5 2000/11/21 16:43:37 bjornw + * Fixed so it compiles under CONFIG_SVINTO_SIM + * + * Revision 1.4 2000/11/15 17:34:12 bjornw + * Added a timeout timer for flushing input channels. The interrupt-based + * fast flush system should be easy to merge with this later (works the same + * way, only with an irq instead of a system timer_list) + * + * Revision 1.3 2000/11/13 17:19:57 bjornw + * * Incredibly, this almost complete rewrite of serial.c worked (at least + * for output) the first time. + * + * Items worth noticing: + * + * No Etrax100 port 1 workarounds (does only compile on 2.4 anyway now) + * RS485 is not ported (why cant it be done in userspace as on x86 ?) + * Statistics done through async_icount - if any more stats are needed, + * that's the place to put them or in an arch-dep version of it. + * timeout_interrupt and the other fast timeout stuff not ported yet + * There be dragons in this 3k+ line driver + * + * Revision 1.2 2000/11/10 16:50:28 bjornw + * First shot at a 2.4 port, does not compile totally yet + * + * Revision 1.1 2000/11/10 16:47:32 bjornw + * Added verbatim copy of rev 1.49 etrax100ser.c from elinux + * + * Revision 1.49 2000/10/30 15:47:14 tobiasa + * Changed version number. + * + * Revision 1.48 2000/10/25 11:02:43 johana + * Changed %ul to %lu in printf's + * + * Revision 1.47 2000/10/18 15:06:53 pkj + * Compile correctly with CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST and + * CONFIG_SERIAL_PROC_ENTRY together. + * Some clean-up of the /proc/serial file. + * + * Revision 1.46 2000/10/16 12:59:40 johana + * Added CONFIG_SERIAL_PROC_ENTRY for statistics and debug info. + * + * Revision 1.45 2000/10/13 17:10:59 pkj + * Do not flush DMAs while flipping TTY buffers. + * + * Revision 1.44 2000/10/13 16:34:29 pkj + * Added a delay in ser_interrupt() for 2.3ms when an error is detected. + * We do not know why this delay is required yet, but without it the + * irmaflash program does not work (this was the program that needed + * the ser_interrupt() to be needed in the first place). This should not + * affect normal use of the serial ports. + * + * Revision 1.43 2000/10/13 16:30:44 pkj + * New version of the fast flush of serial buffers code. This time + * it is localized to the serial driver and uses a fast timer to + * do the work. + * + * Revision 1.42 2000/10/13 14:54:26 bennyo + * Fix for switching RTS when using rs485 + * + * Revision 1.41 2000/10/12 11:43:44 pkj + * Cleaned up a number of comments. + * + * Revision 1.40 2000/10/10 11:58:39 johana + * Made RS485 support generic for all ports. + * Toggle rts in interrupt if no delay wanted. + * WARNING: No true transmitter empty check?? + * Set d_wait bit when sending data so interrupt is delayed until + * fifo flushed. (Fix tcdrain() problem) + * + * Revision 1.39 2000/10/04 16:08:02 bjornw + * * Use virt_to_phys etc. for DMA addresses + * * Removed CONFIG_FLUSH_DMA_FAST hacks + * * Indentation fix + * + * Revision 1.38 2000/10/02 12:27:10 mattias + * * added variable used when using fast flush on serial dma. + * (CONFIG_FLUSH_DMA_FAST) + * + * Revision 1.37 2000/09/27 09:44:24 pkj + * Uncomment definition of SERIAL_HANDLE_EARLY_ERRORS. + * + * Revision 1.36 2000/09/20 13:12:52 johana + * Support for CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS: + * Number of timer ticks between flush of receive fifo (1 tick = 10ms). + * Try 0-3 for low latency applications. Approx 5 for high load + * applications (e.g. PPP). Maybe this should be more adaptive some day... + * + * Revision 1.35 2000/09/20 10:36:08 johana + * Typo in get_lsr_info() + * + * Revision 1.34 2000/09/20 10:29:59 johana + * Let rs_chars_in_buffer() check fifo content as well. + * get_lsr_info() might work now (not tested). + * Easier to change the port to debug. + * + * Revision 1.33 2000/09/13 07:52:11 torbjore + * Support RS485 + * + * Revision 1.32 2000/08/31 14:45:37 bjornw + * After sending a break we need to reset the transmit DMA channel + * + * Revision 1.31 2000/06/21 12:13:29 johana + * Fixed wait for all chars sent when closing port. + * (Used to always take 1 second!) + * Added shadows for directions of status/ctrl signals. + * + * Revision 1.30 2000/05/29 16:27:55 bjornw + * Simulator ifdef moved a bit + * + * Revision 1.29 2000/05/09 09:40:30 mattias + * * Added description of dma registers used in timeout_interrupt + * * Removed old code + * + * Revision 1.28 2000/05/08 16:38:58 mattias + * * Bugfix for flushing fifo in timeout_interrupt + * Problem occurs when bluetooth stack waits for a small number of bytes + * containing an event acknowledging free buffers in bluetooth HW + * As before, data was stuck in fifo until more data came on uart and + * flushed it up to the stack. + * + * Revision 1.27 2000/05/02 09:52:28 jonasd + * Added fix for peculiar etrax behaviour when eop is forced on an empty + * fifo. This is used when flashing the IRMA chip. Disabled by default. + * + * Revision 1.26 2000/03/29 15:32:02 bjornw + * 2.0.34 updates + * + * Revision 1.25 2000/02/16 16:59:36 bjornw + * * Receive DMA directly into the flip-buffer, eliminating an intermediary + * receive buffer and a memcpy. Will avoid some overruns. + * * Error message on debug port if an overrun or flip buffer overrun occurs. + * * Just use the first byte in the flag flip buffer for errors. + * * Check for timeout on the serial ports only each 5/100 s, not 1/100. + * + * Revision 1.24 2000/02/09 18:02:28 bjornw + * * Clear serial errors (overrun, framing, parity) correctly. Before, the + * receiver would get stuck if an error occured and we did not restart + * the input DMA. + * * Cosmetics (indentation, some code made into inlines) + * * Some more debug options + * * Actually shut down the serial port (DMA irq, DMA reset, receiver stop) + * when the last open is closed. Corresponding fixes in startup(). + * * rs_close() "tx FIFO wait" code moved into right place, bug & -> && fixed + * and make a special case out of port 1 (R_DMA_CHx_STATUS is broken for that) + * * e100_disable_rx/enable_rx just disables/enables the receiver, not RTS + * + * Revision 1.23 2000/01/24 17:46:19 johana + * Wait for flush of DMA/FIFO when closing port. + * + * Revision 1.22 2000/01/20 18:10:23 johana + * Added TIOCMGET ioctl to return modem status. + * Implemented modem status/control that works with the extra signals + * (DTR, DSR, RI,CD) as well. + * 3 different modes supported: + * ser0 on PB (Bundy), ser1 on PB (Lisa) and ser2 on PA (Bundy) + * Fixed DEF_TX value that caused the serial transmitter pin (txd) to go to 0 when + * closing the last filehandle, NASTY!. + * Added break generation, not tested though! + * Use SA_SHIRQ when request_irq() for ser2 and ser3 (shared with) par0 and par1. + * You can't use them at the same time (yet..), but you can hopefully switch + * between ser2/par0, ser3/par1 with the same kernel config. + * Replaced some magic constants with defines + * + * + */ + +static char *serial_version = "$Revision: 1.6 $"; + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= 131343) +#include +#endif +#if (LINUX_VERSION_CODE >= 131336) +#include +#endif +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* non-arch dependant serial structures are in linux/serial.h */ +#include +/* while we keep our own stuff (struct e100_serial) in a local .h file */ +#include "serial.h" + +/* + * All of the compatibilty code so we can compile serial.c against + * older kernels is hidden in serial_compat.h + */ +#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */ +#include "serial_compat.h" +#endif + +static DECLARE_TASK_QUEUE(tq_serial); + +struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* serial subtype definitions */ +#ifndef SERIAL_TYPE_NORMAL +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 +#endif + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +//#define SERIAL_DEBUG_INTR +//#define SERIAL_DEBUG_OPEN +//#define SERIAL_DEBUG_FLOW +//#define SERIAL_DEBUG_DATA +//#define SERIAL_DEBUG_THROTTLE +//#define SERIAL_DEBUG_IO /* Debug for Extra control and status pins */ +#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */ + +/* Enable this to use serial interrupts to handle when you + expect the first received event on the serial port to + be an error, break or similar. Used to be able to flash IRMA + from eLinux */ +//#define SERIAL_HANDLE_EARLY_ERRORS + + +#ifndef CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS +/* Default number of timer ticks before flushing rx fifo + * When using "little data, low latency applications: use 0 + * When using "much data applications (PPP)" use ~5 + */ +#define CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS 5 +#endif + +#define MAX_FLUSH_TIME 8 + +#define _INLINE_ inline + +static void change_speed(struct e100_serial *info); +static void rs_wait_until_sent(struct tty_struct *tty, int timeout); +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count); + +#define DEF_BAUD 0x99 /* 115.2 kbit/s */ +#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST ) +#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */ +/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */ +#define DEF_TX 0x80 /* or SERIAL_CTRL_B */ + +/* offsets from R_SERIALx_CTRL */ + +#define REG_DATA 0 +#define REG_TR_DATA 0 +#define REG_STATUS 1 +#define REG_TR_CTRL 1 +#define REG_REC_CTRL 2 +#define REG_BAUD 3 +#define REG_XOFF 4 /* this is a 32 bit register */ + +/* this is the data for the four serial ports in the etrax100 */ +/* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */ +/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */ + +static struct e100_serial rs_table[] = { + { DEF_BAUD, (unsigned char *)R_SERIAL0_CTRL, 1U << 12, /* uses DMA 6 and 7 */ + R_DMA_CH6_CLR_INTR, R_DMA_CH6_FIRST, R_DMA_CH6_CMD, + R_DMA_CH6_STATUS, R_DMA_CH6_HWSW, + R_DMA_CH7_CLR_INTR, R_DMA_CH7_FIRST, R_DMA_CH7_CMD, + R_DMA_CH7_STATUS, R_DMA_CH7_HWSW, + STD_FLAGS, DEF_RX, DEF_TX, 2 }, /* ttyS0 */ +#ifndef CONFIG_SVINTO_SIM + { DEF_BAUD, (unsigned char *)R_SERIAL1_CTRL, 1U << 16, /* uses DMA 8 and 9 */ + R_DMA_CH8_CLR_INTR, R_DMA_CH8_FIRST, R_DMA_CH8_CMD, + R_DMA_CH8_STATUS, R_DMA_CH8_HWSW, + R_DMA_CH9_CLR_INTR, R_DMA_CH9_FIRST, R_DMA_CH9_CMD, + R_DMA_CH9_STATUS, R_DMA_CH9_HWSW, + STD_FLAGS, DEF_RX, DEF_TX, 3 }, /* ttyS1 */ + + { DEF_BAUD, (unsigned char *)R_SERIAL2_CTRL, 1U << 4, /* uses DMA 2 and 3 */ + R_DMA_CH2_CLR_INTR, R_DMA_CH2_FIRST, R_DMA_CH2_CMD, + R_DMA_CH2_STATUS, R_DMA_CH2_HWSW, + R_DMA_CH3_CLR_INTR, R_DMA_CH3_FIRST, R_DMA_CH3_CMD, + R_DMA_CH3_STATUS, R_DMA_CH3_HWSW, + STD_FLAGS, DEF_RX, DEF_TX, 0 }, /* ttyS2 */ + + { DEF_BAUD, (unsigned char *)R_SERIAL3_CTRL, 1U << 8, /* uses DMA 4 and 5 */ + R_DMA_CH4_CLR_INTR, R_DMA_CH4_FIRST, R_DMA_CH4_CMD, + R_DMA_CH4_STATUS, R_DMA_CH4_HWSW, + R_DMA_CH5_CLR_INTR, R_DMA_CH5_FIRST, R_DMA_CH5_CMD, + R_DMA_CH5_STATUS, R_DMA_CH5_HWSW, + STD_FLAGS, DEF_RX, DEF_TX, 1 } /* ttyS3 */ +#endif +}; + + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) + +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + + +/* RS-485 */ +#if defined(CONFIG_RS485) +#if defined(CONFIG_RS485_ON_PA) +static int rs485_pa_bit = CONFIG_RS485_ON_PA_BIT; +#endif +#endif + + +/* For now we assume that all bits are on the same port for each serial port */ + +/* Dummy shadow variables */ +static unsigned char dummy_ser0 = 0x00; +static unsigned char dummy_ser1 = 0x00; +static unsigned char dummy_ser2 = 0x00; +static unsigned char dummy_ser3 = 0x00; + +static unsigned char dummy_dir_ser0 = 0x00; +static unsigned char dummy_dir_ser1 = 0x00; +static unsigned char dummy_dir_ser2 = 0x00; +static unsigned char dummy_dir_ser3 = 0x00; + +/* Info needed for each ports extra control/status signals. + We only supports that all pins uses same register for each port */ +struct control_pins +{ + volatile unsigned char *port; + volatile unsigned char *shadow; + volatile unsigned char *dir_shadow; + + unsigned char dtr_bit; + unsigned char ri_bit; + unsigned char dsr_bit; + unsigned char cd_bit; +}; + +static const struct control_pins e100_modem_pins[NR_PORTS] = +{ +/* Ser 0 */ + { +#if defined(CONFIG_ETRAX100_SER0_DTR_RI_DSR_CD_ON_PB) + R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, + CONFIG_ETRAX100_SER0_DTR_ON_PB_BIT, + CONFIG_ETRAX100_SER0_RI_ON_PB_BIT, + CONFIG_ETRAX100_SER0_DSR_ON_PB_BIT, + CONFIG_ETRAX100_SER0_CD_ON_PB_BIT +#else + &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3 +#endif + }, +/* Ser 1 */ + { +#if defined(CONFIG_ETRAX100_SER1_DTR_RI_DSR_CD_ON_PB) + R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, + CONFIG_ETRAX100_SER1_DTR_ON_PB_BIT, + CONFIG_ETRAX100_SER1_RI_ON_PB_BIT, + CONFIG_ETRAX100_SER1_DSR_ON_PB_BIT, + CONFIG_ETRAX100_SER1_CD_ON_PB_BIT +#else + &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3 +#endif + }, +/* Ser 2 */ + { +#if defined(CONFIG_ETRAX100_SER2_DTR_RI_DSR_CD_ON_PA) + R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow, + CONFIG_ETRAX100_SER2_DTR_ON_PA_BIT, + CONFIG_ETRAX100_SER2_RI_ON_PA_BIT, + CONFIG_ETRAX100_SER2_DSR_ON_PA_BIT, + CONFIG_ETRAX100_SER2_CD_ON_PA_BIT +#else + &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3 +#endif + }, +/* Ser 3 */ + { + &dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3 + } +}; + +#if defined(CONFIG_RS485) && defined(CONFIG_RS485_ON_PA) +unsigned char rs485_pa_port = CONFIG_RS485_ON_PA_BIT; +#endif + +#define E100_RTS_MASK 0x20 +#define E100_CTS_MASK 0x40 + + +/* All serial port signals are active low: + * active = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level + * inactive = 1 -> 0V to RS-232 driver -> +12V on RS-232 level + * + * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip + */ + +/* Output */ +#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK) +/* Input */ +#define E100_CTS_GET(info) ((info)->port[REG_STATUS] & E100_CTS_MASK) + +/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */ +/* Is an output */ +#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].shadow) & (1 << e100_modem_pins[(info)->line].dtr_bit)) + +/* Normally inputs */ +#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].ri_bit)) +#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].cd_bit)) + +/* Input */ +#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].dsr_bit)) + + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the memcpy_fromfs blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char *tmp_buf; +#ifdef DECLARE_MUTEX +static DECLARE_MUTEX(tmp_buf_sem); +#else +static struct semaphore tmp_buf_sem = MUTEX; +#endif + +#ifdef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST +#define TIMER1_IRQ_NBR 3 + +/* clock select 10 for timer 1 gives 230400 Hz */ +#define FASTTIMER_SELECT (10) +/* we use a source of 230400 Hz and a divider of 15 => 15360 Hz */ +#define FASTTIMER_DIV (15) + +/* fast flush timer stuff */ +static int fast_timer_started = 0; +static unsigned long int fast_timer_ints = 0; + +static void _INLINE_ start_flush_timer(void) +{ + if (fast_timer_started) + return; + + *R_TIMER_CTRL = r_timer_ctrl_shadow = + (r_timer_ctrl_shadow & + ~IO_MASK(R_TIMER_CTRL, timerdiv1) & + ~IO_MASK(R_TIMER_CTRL, tm1) & + ~IO_MASK(R_TIMER_CTRL, clksel1)) | + IO_FIELD(R_TIMER_CTRL, timerdiv1, FASTTIMER_DIV) | + IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | + IO_FIELD(R_TIMER_CTRL, clksel1, FASTTIMER_SELECT); + + *R_TIMER_CTRL = r_timer_ctrl_shadow = + (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | + IO_STATE(R_TIMER_CTRL, tm1, run); + + /* enable timer1 irq */ + + *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); + fast_timer_started = 1; +} +#endif /* CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST */ + +/* + * This function maps from the Bxxxx defines in asm/termbits.h into real + * baud rates. + */ + +static int +cflag_to_baud(unsigned int cflag) +{ + static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, + 4800, 9600, 19200, 38400 }; + + static int ext_baud_table[] = { + 0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000 }; + + if(cflag & CBAUDEX) + return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; + else + return baud_table[cflag & CBAUD]; +} + +/* and this maps to an etrax100 hardware baud constant */ + +static unsigned char +cflag_to_etrax_baud(unsigned int cflag) +{ + char retval; + + static char baud_table[] = { + -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 }; + + static char ext_baud_table[] = { + -1, 8, 9, 10, 11, 12, 13, 14 }; + + if(cflag & CBAUDEX) + retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX]; + else + retval = baud_table[cflag & CBAUD]; + + if(retval < 0) { + printk("serdriver tried setting invalid baud rate, flags %x.\n", cflag); + retval = 5; /* choose default 9600 instead */ + } + + return retval | (retval << 4); /* choose same for both TX and RX */ +} + + +/* Various static support functions */ + +/* Functions to set or clear DTR/RTS on the requested line */ +/* It is complicated by the fact that RTS is a serial port register, while + * DTR might not be implemented in the HW at all, and if it is, it can be on + * any general port. + */ + +static inline void +e100_dtr(struct e100_serial *info, int set) +{ +#ifndef CONFIG_SVINTO_SIM + unsigned char mask = ( 1 << e100_modem_pins[info->line].dtr_bit); +#ifdef SERIAL_DEBUG_IO + printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); + printk("ser%i shadow before 0x%02X get: %i\n", + info->line, *e100_modem_pins[info->line].shadow, + E100_DTR_GET(info)); +#endif + /* DTR is active low */ + { + unsigned long flags; + save_flags(flags); + cli(); + *e100_modem_pins[info->line].shadow &= ~mask; + *e100_modem_pins[info->line].shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow; + restore_flags(flags); + } + +#if 0 + REG_SHADOW_SET(e100_modem_pins[info->line].port, + *e100_modem_pins[info->line].shadow, + e100_modem_pins[info->line].dtr_bit, !set); +#endif +#ifdef SERIAL_DEBUG_IO + printk("ser%i shadow after 0x%02X get: %i\n", + info->line, *e100_modem_pins[info->line].shadow, + E100_DTR_GET(info)); +#endif +#endif +} + +/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive + * 0=0V , 1=3.3V + */ +static inline void +e100_rts(struct e100_serial *info, int set) +{ +#ifndef CONFIG_SVINTO_SIM +#ifdef SERIAL_DEBUG_IO + printk("ser%i rts %i\n", info->line, set); +#endif + info->rx_ctrl &= ~E100_RTS_MASK; + info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ + info->port[REG_REC_CTRL] = info->rx_ctrl; +#endif +} + +/* If this behaves as a modem, RI and CD is an output */ +static inline void +e100_ri_out(struct e100_serial *info, int set) +{ +#ifndef CONFIG_SVINTO_SIM + /* RI is active low */ + { + unsigned char mask = ( 1 << e100_modem_pins[info->line].ri_bit); + unsigned long flags; + save_flags(flags); + cli(); + *e100_modem_pins[info->line].shadow &= ~mask; + *e100_modem_pins[info->line].shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow; + restore_flags(flags); + } +#if 0 + REG_SHADOW_SET(e100_modem_pins[info->line].port, + *e100_modem_pins[info->line].shadow, + e100_modem_pins[info->line].ri_bit, !set); +#endif +#endif +} +static inline void +e100_cd_out(struct e100_serial *info, int set) +{ +#ifndef CONFIG_SVINTO_SIM + /* CD is active low */ + { + unsigned char mask = ( 1 << e100_modem_pins[info->line].cd_bit); + unsigned long flags; + save_flags(flags); + cli(); + *e100_modem_pins[info->line].shadow &= ~mask; + *e100_modem_pins[info->line].shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow; + restore_flags(flags); + } +#if 0 + REG_SHADOW_SET(e100_modem_pins[info->line].port, + *e100_modem_pins[info->line].shadow, + e100_modem_pins[info->line].cd_bit, !set); +#endif +#endif +} + +static inline void +e100_disable_rx(struct e100_serial *info) +{ +#ifndef CONFIG_SVINTO_SIM + /* disable the receiver */ + info->port[REG_REC_CTRL] = (info->rx_ctrl &= ~0x40); +#endif +} + +static inline void +e100_enable_rx(struct e100_serial *info) +{ +#ifndef CONFIG_SVINTO_SIM + /* enable the receiver */ + info->port[REG_REC_CTRL] = (info->rx_ctrl |= 0x40); +#endif +} + +/* the rx DMA uses both the dma_descr and the dma_eop interrupts */ + +static inline void +e100_disable_rxdma_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("rxdma_irq(%d): 0\n",info->line); +#endif + *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3); +} + +static inline void +e100_enable_rxdma_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("rxdma_irq(%d): 1\n",info->line); +#endif + *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3); +} + +/* the tx DMA uses only dma_descr interrupt */ + +static inline void +e100_disable_txdma_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("txdma_irq(%d): 0\n",info->line); +#endif + *R_IRQ_MASK2_CLR = info->irq; +} + +static inline void +e100_enable_txdma_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("txdma_irq(%d): 1\n",info->line); +#endif + *R_IRQ_MASK2_SET = info->irq; +} + +#ifdef SERIAL_HANDLE_EARLY_ERRORS +/* in order to detect and fix errors on the first byte + we have to use the serial interrupts as well. */ + +static inline void +e100_disable_serial_data_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("ser_irq(%d): 0\n",info->line); +#endif + *R_IRQ_MASK1_CLR = (1U << (8+2*info->line)); +} + +static inline void +e100_enable_serial_data_irq(struct e100_serial *info) +{ +#ifdef SERIAL_DEBUG_INTR + printk("ser_irq(%d): 1\n",info->line); + printk("**** %d = %d\n", + (8+2*info->line), + (1U << (8+2*info->line))); +#endif + *R_IRQ_MASK1_SET = (1U << (8+2*info->line)); +} +#endif + +#if defined(CONFIG_RS485) +/* Enable RS-485 mode on selected port. This is UGLY. */ +static int +e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r) +{ + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + +#if defined(CONFIG_RS485_ON_PA) + *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); +#endif + + info->rs485.rts_on_send = 0x01 & r->rts_on_send; + info->rs485.rts_after_sent = 0x01 & r->rts_after_sent; + info->rs485.delay_rts_before_send = r->delay_rts_before_send; + info->rs485.enabled = r->enabled; + + return 0; +} + +/* Enable RS-485 mode on selected port. This is UGLY. */ +static int +e100_write_rs485(struct tty_struct *tty,struct rs485_write *r) +{ + int stop_delay; + int total, i; + int max_j, delay_ms, bits; + tcflag_t cflags; + int size = (*r).outc_size; + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + struct wait_queue wait = { current, NULL }; + + /* If we are in RS-485 mode, we need to toggle RTS and disable + * the receiver before initiating a DMA transfer + */ + e100_rts(info, info->rs485.rts_on_send); +#if defined(CONFIG_RS485_DISABLE_RECEIVER) + e100_disable_rx(info); + e100_disable_rxdma_irq(info); +#endif + + if (info->rs485.delay_rts_before_send > 0){ + current->timeout = jiffies + (info->rs485.delay_rts_before_send * HZ)/1000; + current->state = TASK_INTERRUPTIBLE; + schedule(); + current->timeout = 0; + } + total = rs_write(tty, 1, (*r).outc, (*r).outc_size); + + /* If we are in RS-485 mode the following things has to be done: + * wait until DMA is ready + * wait on transmit shift register + * wait to toggle RTS + * enable the receiver + */ + + /* wait on transmit shift register */ + /* All is sent, check if we should wait more before toggling rts */ + + /* calc. number of bits / data byte */ + cflags = info->tty->termios->c_cflag; + /* databits + startbit and 1 stopbit */ + if((cflags & CSIZE) == CS7) + bits = 9; + else + bits = 10; + + if(cflags & CSTOPB) /* 2 stopbits ? */ + bits++; + + if(cflags & PARENB) /* parity bit ? */ + bits++; + + /* calc timeout */ + delay_ms = ((bits * size * 1000) / info->baud) + 1; + max_j = jiffies + (delay_ms * HZ)/1000 + 10; + + while (jiffies < max_j ) { + if (info->port[REG_STATUS] & 0x20) { + for( i=0 ; i<100; i++ ) {}; + if (info->port[REG_STATUS] & 0x20) { + /* ~25 for loops per usec */ + stop_delay = 25 * (1000000 / info->baud); + if(cflags & CSTOPB) + stop_delay *= 2; + for( i=0 ; irs485.rts_after_sent); + +#if defined(CONFIG_RS485_DISABLE_RECEIVER) + e100_enable_rx(info); + e100_enable_rxdma_irq(info); +#endif + + return total; +} +#endif + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ + +/* FIXME - when are these used and what is the purpose ? + * In rs_stop we probably just can block the transmit DMA ready irq + * and in rs_start we re-enable it (and then the old one will come). + */ + +static void +rs_stop(struct tty_struct *tty) +{ +} + +static void +rs_start(struct tty_struct *tty) +{ +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static _INLINE_ void +rs_sched_event(struct e100_serial *info, + int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +/* The output DMA channel is free - use it to send as many chars as possible + * NOTES: + * We don't pay attention to info->x_char, which means if the TTY wants to + * use XON/XOFF it will set info->x_char but we won't send any X char! + * + * To implement this, we'd just start a DMA send of 1 byte pointing at a + * buffer containing the X char, and skip updating xmit. We'd also have to + * check if the last sent char was the X char when we enter this function + * the next time, to avoid updating xmit with the sent X value. + */ + +static void +transmit_chars(struct e100_serial *info) +{ + unsigned int c, sentl; + struct etrax_dma_descr *descr; + +#ifdef CONFIG_SVINTO_SIM + /* This will output too little if tail is not 0 always since + * we don't reloop to send the other part. Anyway this SHOULD be a + * no-op - transmit_chars would never really be called during sim + * since rs_write does not write into the xmit buffer then. + */ + if(info->xmit.tail) + printk("Error in serial.c:transmit_chars(), tail!=0\n"); + if(info->xmit.head != info->xmit.tail) { + SIMCOUT(info->xmit.buf + info->xmit.tail, + CIRC_CNT(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE)); + info->xmit.head = info->xmit.tail; /* move back head */ + info->tr_running = 0; + } + return; +#endif + /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ + *info->oclrintradr = 3; + +#ifdef SERIAL_DEBUG_INTR + if(info->line == SERIAL_DEBUG_LINE) + printk("tc\n"); +#endif + if(!info->tr_running) { + /* weirdo... we shouldn't get here! */ + printk("Achtung: transmit_chars with !tr_running\n"); + return; + } + + descr = &info->tr_descr; + + /* first get the amount of bytes sent during the last DMA transfer, + and update xmit accordingly */ + + /* if the stop bit was not set, all data has been sent */ + if(!(descr->status & d_stop)) { + sentl = descr->sw_len; + } else + /* otherwise we find the amount of data sent here */ + sentl = descr->hw_len; + + /* update stats */ + info->icount.tx += sentl; + + /* update xmit buffer */ + info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1); + + /* if there is only a few chars left in the buf, wake up the blocked + write if any */ + if (CIRC_CNT(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + + /* find out the largest amount of consecutive bytes we want to send now */ + + c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); + + if(c <= 0) { + /* our job here is done, don't schedule any new DMA transfer */ + info->tr_running = 0; + +#if defined(CONFIG_RS485) + /* Check if we should toggle RTS now */ + if (info->rs485.enabled) + { + /* Make sure fifo is empty */ + int in_fifo = 0 ; + do{ + in_fifo = (*info->ostatusadr) & 0x007F ; + } while (in_fifo > 0) ; + /* Any way to really check transmitter empty? (TEMT) */ + /* Control RTS to set to RX mode */ + e100_rts(info, info->rs485.rts_after_sent); +#if defined(CONFIG_RS485_DISABLE_RECEIVER) + e100_enable_rx(info); + e100_enable_rxdma_irq(info); +#endif + } +#endif /* RS485 */ + + return; + } + + /* ok we can schedule a dma send of c chars starting at info->xmit.tail */ + /* set up the descriptor correctly for output */ + + descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */ + descr->sw_len = c; + descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail); + descr->status = 0; + + *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */ + *info->ocmdadr = 1; /* dma command start -> R_DMAx_CMD */ + + /* DMA is now running (hopefully) */ + +} + +static void +start_transmit(struct e100_serial *info) +{ +#if 0 + if(info->line == SERIAL_DEBUG_LINE) + printk("x\n"); +#endif + + info->tr_descr.sw_len = 0; + info->tr_descr.hw_len = 0; + info->tr_descr.status = 0; + info->tr_running = 1; + + transmit_chars(info); +} + + +static _INLINE_ void +receive_chars(struct e100_serial *info) +{ + struct tty_struct *tty; + unsigned char rstat; + unsigned int recvl; + struct etrax_dma_descr *descr; + +#ifdef CONFIG_SVINTO_SIM + /* No receive in the simulator. Will probably be when the rest of + * the serial interface works, and this piece will just be removed. + */ + return; +#endif + + tty = info->tty; + + /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */ + + *info->iclrintradr = 3; + + if(!tty) /* something wrong... */ + return; + + descr = &info->rec_descr; + + /* find out how many bytes were read */ + + /* if the eop bit was not set, all data has been received */ + if(!(descr->status & d_eop)) { + recvl = descr->sw_len; + } else { + /* otherwise we find the amount of data received here */ + recvl = descr->hw_len; + } + if(recvl) { + unsigned char *buf; + struct async_icount *icount; + + icount = &info->icount; + + /* update stats */ + icount->rx += recvl; + + /* read the status register so we can detect errors */ + rstat = info->port[REG_STATUS]; + + if(rstat & 0xe) { + /* if we got an error, we must reset it by reading the + * data_in field + */ + (void)info->port[REG_DATA]; + } + + /* we only ever write errors into the first byte in the flip + * flag buffer, so we dont have to clear it all every time + */ + + if(rstat & 0x04) { + icount->parity++; + *tty->flip.flag_buf_ptr = TTY_PARITY; + } else if(rstat & 0x08) { + icount->overrun++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } else if(rstat & 0x02) { + icount->frame++; + *tty->flip.flag_buf_ptr = TTY_FRAME; + } else + *tty->flip.flag_buf_ptr = 0; + + /* use the flip buffer next in turn to restart DMA into */ + + if (tty->flip.buf_num) { + buf = tty->flip.char_buf; + } else { + buf = tty->flip.char_buf + TTY_FLIPBUF_SIZE; + } + + if(buf == phys_to_virt(descr->buf)) { + printk("ttyS%d flip-buffer overrun!\n", info->line); + icount->overrun++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + /* restart old buffer */ + } else { + descr->buf = virt_to_phys(buf); + + /* schedule or push a flip of the buffer */ + + info->tty->flip.count = recvl; + +#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ + /* this includes a check for low-latency */ + tty_flip_buffer_push(tty); +#else + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); +#endif + } + } + + /* restart the receiving dma */ + + descr->sw_len = TTY_FLIPBUF_SIZE; + descr->ctrl = d_int | d_eol | d_eop; + descr->hw_len = 0; + descr->status = 0; + + *info->ifirstadr = virt_to_phys(descr); + *info->icmdadr = 1; /* start */ + +#ifdef SERIAL_HANDLE_EARLY_ERRORS + e100_enable_serial_data_irq(info); +#endif + /* input dma should be running now */ +} + +static void +start_receive(struct e100_serial *info) +{ + struct etrax_dma_descr *descr; + +#ifdef CONFIG_SVINTO_SIM + /* No receive in the simulator. Will probably be when the rest of + * the serial interface works, and this piece will just be removed. + */ + return; +#endif + + /* reset the input dma channel to be sure it works */ + + *info->icmdadr = 4; + while((*info->icmdadr & 7) == 4); + + descr = &info->rec_descr; + + /* start the receiving dma into the flip buffer */ + + descr->ctrl = d_int | d_eol | d_eop; + descr->sw_len = TTY_FLIPBUF_SIZE; + descr->buf = virt_to_phys(info->tty->flip.char_buf_ptr); + descr->hw_len = 0; + descr->status = 0; + + info->tty->flip.count = 0; + + *info->ifirstadr = virt_to_phys(descr); + *info->icmdadr = 1; /* start */ +} + + +static _INLINE_ void +status_handle(struct e100_serial *info, unsigned short status) +{ +} + +/* the bits in the MASK2 register are laid out like this: + DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR + where I is the input channel and O is the output channel for the port. + info->irq is the bit number for the DMAO_DESCR so to check the others we + shift info->irq to the left. +*/ + +/* dma output channel interrupt handler + this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or + DMA8(ser1) when they have finished a descriptor with the intr flag set. +*/ + +static void +tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct e100_serial *info; + unsigned long ireg; + int i; + +#ifdef CONFIG_SVINTO_SIM + /* No receive in the simulator. Will probably be when the rest of + * the serial interface works, and this piece will just be removed. + */ + { + const char *s = "What? tr_interrupt in simulator??\n"; + SIMCOUT(s,strlen(s)); + } + return; +#endif + + /* find out the line that caused this irq and get it from rs_table */ + + ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ + + for(i = 0; i < NR_PORTS; i++) { + info = rs_table + i; + /* check for dma_descr (dont need to check for dma_eop in output dma for serial */ + if(ireg & info->irq) { + /* we can send a new dma bunch. make it so. */ + transmit_chars(info); + } + + /* FIXME: here we should really check for a change in the + status lines and if so call status_handle(info) */ + } +} + +/* dma input channel interrupt handler */ + +static void +rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct e100_serial *info; + unsigned long ireg; + int i; + +#ifdef CONFIG_SVINTO_SIM + /* No receive in the simulator. Will probably be when the rest of + * the serial interface works, and this piece will just be removed. + */ + { + const char *s = "What? rec_interrupt in simulator??\n"; + SIMCOUT(s,strlen(s)); + } + return; +#endif + + /* find out the line that caused this irq and get it from rs_table */ + + ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */ + + for(i = 0; i < NR_PORTS; i++) { + info = rs_table + i; + /* check for both dma_eop and dma_descr for the input dma channel */ + if(ireg & ((info->irq << 2) | (info->irq << 3))) { + /* we have received something */ + receive_chars(info); + } + + /* FIXME: here we should really check for a change in the + status lines and if so call status_handle(info) */ + } +} + +/* dma fifo/buffer timeout handler + forces an end-of-packet for the dma input channel if no chars + have been received for CONFIG_ETRAX100_RX_TIMEOUT_TICKS/100 s. + If CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST is configured then this + handler is instead run at 15360 Hz. +*/ + +#ifndef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST +static int timeout_divider = 0; +#endif + +static struct timer_list flush_timer; + +static void +timed_flush_handler(void) +{ + struct e100_serial *info; + int i; + unsigned int magic; + +#ifdef CONFIG_SVINTO_SIM + return; +#endif + + for(i = 0; i < NR_PORTS; i++) { + info = rs_table + i; + if(!(info->flags & ASYNC_INITIALIZED)) + continue; + + /* istatusadr (bit 6-0) hold number of bytes in fifo + * ihwswadr (bit 31-16) holds number of bytes in dma buffer + * ihwswadr (bit 15-0) specifies size of dma buffer + */ + + magic = (*info->istatusadr & 0x3f); + magic += ((*info->ihwswadr&0xffff ) - (*info->ihwswadr >> 16)); + + /* if magic is equal to fifo_magic (magic in previous + * timeout_interrupt) then no new data has arrived since last + * interrupt and we'll force eop to flush fifo+dma buffers + */ + + if(magic != info->fifo_magic) { + info->fifo_magic = magic; + info->fifo_didmagic = 0; + } else { + /* hit the timeout, force an EOP for the input + * dma channel if we haven't already + */ + if(!info->fifo_didmagic && magic) { + info->fifo_didmagic = 1; + info->fifo_magic = 0; + *R_SET_EOP = 1U << info->iseteop; + } + } + } + + /* restart flush timer */ + + mod_timer(&flush_timer, jiffies + MAX_FLUSH_TIME); +} + + +#ifdef SERIAL_HANDLE_EARLY_ERRORS + +/* If there is an error (ie break) when the DMA is running and + * there are no bytes in the fifo the DMA is stopped and we get no + * eop interrupt. Thus we have to monitor the first bytes on a DMA + * transfer, and if it is without error we can turn the serial + * interrupts off. + */ + +static void +ser_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct e100_serial *info; + int i; + unsigned char rstat; + + for(i = 0; i < NR_PORTS; i++) { + + info = rs_table + i; + rstat = info->port[REG_STATUS]; + + if(*R_IRQ_MASK1_RD & (1U << (8+2*info->line))) { /* This line caused the irq */ +#ifdef SERIAL_DEBUG_INTR + printk("Interrupt from serport %d\n", i); +#endif + if(rstat & 0x0e) { + /* FIXME: This is weird, but if this delay is + * not present then irmaflash does not work... + */ + udelay(2300); + + /* if we got an error, we must reset it by + * reading the data_in field + */ + (void)info->port[REG_DATA]; + + PROCSTAT(early_errors_cnt[info->line]++); + + /* restart the DMA */ + *info->icmdadr = 3; + } + else { /* it was a valid byte, now let the dma do the rest */ +#ifdef SERIAL_DEBUG_INTR + printk("** OK, disabling ser_interupts\n"); +#endif + e100_disable_serial_data_irq(info); + } + } + } +} +#endif + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void +do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void +do_softint(void *private_) +{ + struct e100_serial *info = (struct e100_serial *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> rs_hangup() + * + */ +static void +do_serial_hangup(void *private_) +{ + struct e100_serial *info = (struct e100_serial *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + tty_hangup(tty); +} + +static int +startup(struct e100_serial * info) +{ + unsigned long flags; + unsigned long page; + + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + /* if it was already initialized, skip this */ + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + restore_flags(flags); + return -EBUSY; + } + + if (info->xmit.buf) + free_page(page); + else + info->xmit.buf = (unsigned char *) page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit_buf); +#endif + + if(info->tty) { + + /* clear the tty flip flag buffer since we will not + * be using it (we only use the first byte..) + */ + + memset(info->tty->flip.flag_buf, 0, TTY_FLIPBUF_SIZE * 2); + } + + save_flags(flags); + cli(); + +#ifdef CONFIG_SVINTO_SIM + /* Bits and pieces collected from below. Better to have them + in one ifdef:ed clause than to mix in a lot of ifdefs, + right? */ + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit.head = info->xmit.tail = 0; + + /* No real action in the simulator, but may set info important + to ioctl. */ + change_speed(info); +#else + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + + /* + * Reset the DMA channels and make sure their interrupts are cleared + */ + + *info->icmdadr = 4; /* reset command */ + *info->ocmdadr = 4; /* reset command */ + + while((*info->icmdadr & 7) == 4); /* wait until reset cycle is complete */ + while((*info->ocmdadr & 7) == 4); + + *info->iclrintradr = 3; /* make sure the irqs are cleared */ + *info->oclrintradr = 3; + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + + info->xmit.head = info->xmit.tail = 0; + + /* + * and set the speed and other flags of the serial port + * this will start the rx/tx as well + */ +#ifdef SERIAL_HANDLE_EARLY_ERRORS + e100_enable_serial_data_irq(info); +#endif + change_speed(info); + + /* dummy read to reset any serial errors */ + + (void)info->port[REG_DATA]; + + /* enable the interrupts */ + + e100_enable_txdma_irq(info); + e100_enable_rxdma_irq(info); + + info->tr_running = 0; /* to be sure we dont lock up the transmitter */ + + /* setup the dma input descriptor and start dma */ + + start_receive(info); + + /* for safety, make sure the descriptors last result is 0 bytes written */ + + info->tr_descr.sw_len = 0; + info->tr_descr.hw_len = 0; + info->tr_descr.status = 0; + + /* enable RTS/DTR last */ + + e100_rts(info, 1); + e100_dtr(info, 1); + +#endif /* CONFIG_SVINTO_SIM */ + + info->flags |= ASYNC_INITIALIZED; + + restore_flags(flags); + return 0; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void +shutdown(struct e100_serial * info) +{ + unsigned long flags; + +#ifndef CONFIG_SVINTO_SIM + /* shut down the transmitter and receiver */ + + e100_disable_rx(info); + info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); + + e100_disable_rxdma_irq(info); + e100_disable_txdma_irq(info); + + info->tr_running = 0; + + /* reset both dma channels */ + + *info->icmdadr = 4; + *info->ocmdadr = 4; + +#endif /* CONFIG_SVINTO_SIM */ + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....\n", info->line, + info->irq); +#endif + + save_flags(flags); + cli(); /* Disable interrupts */ + + if (info->xmit.buf) { + unsigned long pg = (unsigned long) info->xmit.buf; + info->xmit.buf = 0; + free_page(pg); + } + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { + /* hang up DTR and RTS if HUPCL is enabled */ + e100_dtr(info, 0); + e100_rts(info, 0); /* could check CRTSCTS before doing this */ + } + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + + +/* change baud rate and other assorted parameters */ + +static void +change_speed(struct e100_serial *info) +{ + unsigned int cflag; + + /* first some safety checks */ + + if(!info->tty || !info->tty->termios) + return; + if (!info->port) + return; + + cflag = info->tty->termios->c_cflag; + + /* possibly, the tx/rx should be disabled first to do this safely */ + + /* change baud-rate and write it to the hardware */ + + info->baud = cflag_to_baud(cflag); + +#ifndef CONFIG_SVINTO_SIM + info->port[REG_BAUD] = cflag_to_etrax_baud(cflag); + /* start with default settings and then fill in changes */ + + info->rx_ctrl &= ~(0x07); /* 8 bit, no/even parity */ + info->tx_ctrl &= ~(0x37); /* 8 bit, no/even parity, 1 stop bit, no cts */ + + if ((cflag & CSIZE) == CS7) { + /* set 7 bit mode */ + info->tx_ctrl |= 0x01; + info->rx_ctrl |= 0x01; + } + + if (cflag & CSTOPB) { + /* set 2 stop bit mode */ + info->tx_ctrl |= 0x10; + } + + if (cflag & PARENB) { + /* enable parity */ + info->tx_ctrl |= 0x02; + info->rx_ctrl |= 0x02; + } + + if (cflag & PARODD) { + /* set odd parity */ + info->tx_ctrl |= 0x04; + info->rx_ctrl |= 0x04; + } + + if (cflag & CRTSCTS) { + /* enable automatic CTS handling */ + info->tx_ctrl |= 0x20; + } + + /* make sure the tx and rx are enabled */ + + info->tx_ctrl |= 0x40; + info->rx_ctrl |= 0x40; + + /* actually write the control regs to the hardware */ + + info->port[REG_TR_CTRL] = info->tx_ctrl; + info->port[REG_REC_CTRL] = info->rx_ctrl; + *((unsigned long *)&info->port[REG_XOFF]) = 0; + +#endif /* CONFIG_SVINTO_SIM */ +} + +/* start transmitting chars NOW */ + +static void +rs_flush_chars(struct tty_struct *tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + if (info->tr_running + || info->xmit.head == info->xmit.tail + || tty->stopped + || tty->hw_stopped + || !info->xmit.buf) + return; + +#ifdef SERIAL_DEBUG_FLOW + printk("rs_flush_chars\n"); +#endif + + /* this protection might not exactly be necessary here */ + + save_flags(flags); + cli(); + start_transmit(info); + restore_flags(flags); +} + +static int +rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + /* first some sanity checks */ + + if (!tty || !info->xmit.buf || !tmp_buf) + return 0; + +#ifdef SERIAL_DEBUG_DATA + if(info->line == SERIAL_DEBUG_LINE) + printk("rs_write (%d), status %d\n", + count, info->port[REG_STATUS]); +#endif + +#ifdef CONFIG_SVINTO_SIM + /* Really simple. The output is here and now. */ + SIMCOUT(buf, count); + return; +#endif + save_flags(flags); + + /* the cli/restore_flags pairs below are needed because the + * DMA interrupt handler moves the info->xmit values. the memcpy + * needs to be in the critical region unfortunately, because we + * need to read xmit values, memcpy, write xmit values in one + * atomic operation... this could perhaps be avoided by more clever + * design. + */ + if(from_user) { + down(&tmp_buf_sem); + while (1) { + int c1; + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c1 = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + if (c1 < c) + c = c1; + memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + cli(); + while(1) { + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + + if (count < c) + c = count; + if (c <= 0) + break; + + memcpy(info->xmit.buf + info->xmit.head, buf, c); + info->xmit.head = (info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1); + buf += c; + count -= c; + ret += c; + } + restore_flags(flags); + } + + /* enable transmitter if not running, unless the tty is stopped + * this does not need IRQ protection since if tr_running == 0 + * the IRQ's are not running anyway for this port. + */ + + if(info->xmit.head != info->xmit.tail + && !tty->stopped && + !tty->hw_stopped && + !info->tr_running) { + start_transmit(info); + } + + return ret; +} + +/* how much space is available in the xmit buffer? */ + +static int +rs_write_room(struct tty_struct *tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +/* How many chars are in the xmit buffer? + * This does not include any chars in the transmitter FIFO. + * Use wait_until_sent for waiting for FIFO drain. + */ + +static int +rs_chars_in_buffer(struct tty_struct *tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + +/* discard everything in the xmit buffer */ + +static void +rs_flush_buffer(struct tty_struct *tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + save_flags(flags); + cli(); + info->xmit.head = info->xmit.tail = 0; + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + * + * Since we don't bother to check for info->x_char in transmit_chars yet, + * we don't really implement this function yet. + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + printk("serial.c:rs_send_xchar not implemented!\n"); + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + /* TODO. */ + } +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void +rs_throttle(struct tty_struct * tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); + + /* Turn off RTS line (do this atomic) should here be an else ?? */ + + save_flags(flags); + cli(); + e100_rts(info, 0); + restore_flags(flags); +} + +static void +rs_unthrottle(struct tty_struct * tty) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } + + /* Assert RTS line (do this atomic) */ + + save_flags(flags); + cli(); + e100_rts(info, 1); + restore_flags(flags); +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int +get_serial_info(struct e100_serial * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + /* this is all probably wrong, there are a lot of fields + * here that we don't have in e100_serial and maybe we + * should set them to something else than 0. + */ + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = (int)info->port; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int +set_serial_info(struct e100_serial * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct e100_serial old_info; + int retval = 0; + + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + return -EFAULT; + + old_info = *info; + + if(!capable(CAP_SYS_ADMIN)) { + if((new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (info->flags & ~ASYNC_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + goto check_and_exit; + } + + if (info->count > 1) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; +#if (LINUX_VERSION_CODE > 0x20100) + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif + + check_and_exit: + if(info->flags & ASYNC_INITIALIZED) { + change_speed(info); + } else + retval = startup(info); + return retval; +} + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int +get_lsr_info(struct e100_serial * info, unsigned int *value) +{ + unsigned int result; + +#ifdef CONFIG_SVINTO_SIM + /* Always open. */ + result = TIOCSER_TEMT; +#else + if (*info->ostatusadr & 0x007F) /* something in fifo */ + result = 0; + else + result = TIOCSER_TEMT; +#endif + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +#ifdef SERIAL_DEBUG_IO +struct state_str +{ + int state; + const char *str; + +}; + +const struct state_str control_state_str[]={ + {TIOCM_DTR, "DTR" }, + {TIOCM_RTS, "RTS"}, + {TIOCM_ST, "ST?" }, + {TIOCM_SR, "SR?" }, + {TIOCM_CTS, "CTS" }, + {TIOCM_CD, "CD" }, + {TIOCM_RI, "RI" }, + {TIOCM_DSR, "DSR" }, + {0, NULL } +}; + +char *get_control_state_str(int MLines, char *s) +{ + int i = 0; + s[0]='\0'; + while (control_state_str[i].str != NULL) { + if (MLines & control_state_str[i].state) { + if (s[0] != '\0') { + strcat(s, ", "); + } + strcat(s, control_state_str[i].str); + } + i++; + } + return s; +} +#endif + +static int +get_modem_info(struct e100_serial * info, unsigned int *value) +{ + unsigned int result; + /* Polarity isn't verified */ +#if 0 /*def SERIAL_DEBUG_IO */ + + printk("get_modem_info: RTS: %i DTR: %i CD: %i RI: %i DSR: %i CTS: %i\n", + E100_RTS_GET(info), + E100_DTR_GET(info), + E100_CD_GET(info), + E100_RI_GET(info), + E100_DSR_GET(info), + E100_CTS_GET(info)); +#endif + result = + (!E100_RTS_GET(info) ? TIOCM_RTS : 0) + | (!E100_DTR_GET(info) ? TIOCM_DTR : 0) + | (!E100_CD_GET(info) ? TIOCM_CAR : 0) + | (!E100_RI_GET(info) ? TIOCM_RNG : 0) + | (!E100_DSR_GET(info) ? TIOCM_DSR : 0) + | (!E100_CTS_GET(info) ? TIOCM_CTS : 0); + +#ifdef SERIAL_DEBUG_IO + printk("e100ser: modem state: %i 0x%08X\n", result, result); + { + char s[100]; + + get_control_state_str(result, s); + printk("state: %s\n", s); + } +#endif + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + + +static int +set_modem_info(struct e100_serial * info, unsigned int cmd, + unsigned int *value) +{ + unsigned int arg; + + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) { + e100_rts(info, 1); + } + if (arg & TIOCM_DTR) { + e100_dtr(info, 1); + } + /* Handle FEMALE behaviour */ + if (arg & TIOCM_RI) { + e100_ri_out(info, 1); + } + if (arg & TIOCM_CD) { + e100_cd_out(info, 1); + } + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) { + e100_rts(info, 0); + } + if (arg & TIOCM_DTR) { + e100_dtr(info, 0); + } + /* Handle FEMALE behaviour */ + if (arg & TIOCM_RI) { + e100_ri_out(info, 0); + } + if (arg & TIOCM_CD) { + e100_cd_out(info, 0); + } + break; + case TIOCMSET: + e100_rts(info, arg & TIOCM_RTS); + e100_dtr(info, arg & TIOCM_DTR); + /* Handle FEMALE behaviour */ + e100_ri_out(info, arg & TIOCM_RI); + e100_cd_out(info, arg & TIOCM_CD); + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * This routine sends a break character out the serial port. + */ +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ +static void +send_break(struct e100_serial * info, int duration) +{ + unsigned long flags; + + if (!info->port) + return; + + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + duration; + + save_flags(flags); + cli(); + + /* Go to manual mode and set the txd pin to 0 */ + + info->tx_ctrl &= 0x3F; /* Clear bit 7 (txd) and 6 (tr_enable) */ + info->port[REG_TR_CTRL] = info->tx_ctrl; + + /* wait for "duration" jiffies */ + + schedule(); + + info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */ + info->port[REG_TR_CTRL] = info->tx_ctrl; + + /* the DMA gets awfully confused if we toggle the tranceiver like this + * so we need to reset it + */ + *info->ocmdadr = 4; + + restore_flags(flags); +} +#else +static void +rs_break(struct tty_struct *tty, int break_state) +{ + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + if (!info->port) + return; + + save_flags(flags); + cli(); + if (break_state == -1) { + /* Go to manual mode and set the txd pin to 0 */ + info->tx_ctrl &= 0x3F; /* Clear bit 7 (txd) and 6 (tr_enable) */ + } else { + info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */ + } + info->port[REG_TR_CTRL] = info->tx_ctrl; + restore_flags(flags); +} +#endif + +static int +rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + int retval; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { +#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + if (!arg) { + send_break(info, HZ/4); /* 1/4 second */ + if (signal_pending(current)) + return -EINTR; + } + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + send_break(info, arg ? arg*(HZ/10) : HZ/4); + if (signal_pending(current)) + return -EINTR; + return 0; + case TIOCGSOFTCAR: + error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); + if (error) + return error; + put_fs_long(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg); + return 0; + case TIOCSSOFTCAR: + arg = get_fs_long((unsigned long *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; +#endif + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + if (copy_to_user((struct e100_serial *) arg, + info, sizeof(struct e100_serial))) + return -EFAULT; + return 0; + +#if defined(CONFIG_RS485) + case TIOCSERSETRS485: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct rs485_control)); + + if (error) + return error; + + return e100_enable_rs485(tty, (struct rs485_control *) arg); + + case TIOCSERWRRS485: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct rs485_write)); + + if (error) + return error; + + return e100_write_rs485(tty, (struct rs485_write *) arg); +#endif + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void +rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + + change_speed(info); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } + +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * S structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void +rs_close(struct tty_struct *tty, struct file * filp) +{ + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + unsigned long flags; + + if (!info) + return; + + /* interrupts are disabled for this entire function */ + + save_flags(flags); + cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("[%d] rs_close ttyS%d, count = %d\n", current->pid, + info->line, info->count); +#endif + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("rs_close: bad serial port count for ttyS%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) { + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the serial receiver and the DMA receive interrupt. + */ +#ifdef SERIAL_HANDLE_EARLY_ERRORS + e100_disable_serial_data_irq(info); +#endif + +#ifndef CONFIG_SVINTO_SIM + e100_disable_rx(info); + e100_disable_rxdma_irq(info); + + if (info->flags & ASYNC_INITIALIZED) { + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important as we have a transmit FIFO! + */ + rs_wait_until_sent(tty, HZ); + } +#endif + + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + restore_flags(flags); + + /* port closed */ + +#if defined(CONFIG_RS485) + if (info->rs485.enabled) { + info->rs485.enabled = 0; +#if defined(CONFIG_RS485_ON_PA) + *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); +#endif + } +#endif +} + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ + unsigned long orig_jiffies; + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + /* + * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO + * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k) + */ + orig_jiffies = jiffies; + while(info->xmit.head != info->xmit.tail || /* More in send queue */ + (*info->ostatusadr & 0x007f)) { /* more in FIFO */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + set_current_state(TASK_RUNNING); +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +void +rs_hangup(struct tty_struct *tty) +{ + struct e100_serial * info = (struct e100_serial *)tty->driver_data; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int +block_til_ready(struct tty_struct *tty, struct file * filp, + struct e100_serial *info) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int retval; + int do_clocal = 0, extra_count = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (info->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttyS%d, count = %d\n", + info->line, info->count); +#endif + save_flags(flags); + cli(); + if (!tty_hung_up_p(filp)) { + extra_count++; + info->count--; + } + restore_flags(flags); + info->blocked_open++; + while (1) { + save_flags(flags); + cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE)) { + /* assert RTS and DTR */ + e100_rts(info, 1); + e100_dtr(info, 1); + } + restore_flags(flags); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && do_clocal) + /* && (do_clocal || DCD_IS_ASSERTED) */ + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttyS%d, count = %d\n", + info->line, info->count); +#endif + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) + info->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttyS%d, count = %d\n", + info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. + * It performs the serial-specific initialization for the tty structure. + */ +static int +rs_open(struct tty_struct *tty, struct file * filp) +{ + struct e100_serial *info; + int retval, line; + unsigned long page; + + /* find which port we want to open */ + + line = MINOR(tty->device) - tty->driver.minor_start; + + if (line < 0 || line >= NR_PORTS) + return -ENODEV; + + /* dont allow opening ports that are not enabled in the HW config */ + +#ifndef CONFIG_ETRAX100_SERIAL_PORT2 + if (line == 2) + return -ENODEV; +#endif +#ifndef CONFIG_ETRAX100_SERIAL_PORT3 + if (line == 3) + return -ENODEV; +#endif + + /* find the corresponding e100_serial struct in the table */ + + info = rs_table + line; + +#ifdef SERIAL_DEBUG_OPEN + printk("[%d] rs_open %s%d, count = %d\n", current->pid, + tty->driver.name, info->line, + info->count); +#endif + + info->count++; + tty->driver_data = info; + info->tty = tty; + +#if (LINUX_VERSION_CODE > 0x20100) + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +#endif + + if (!tmp_buf) { + page = get_zeroed_page(GFP_KERNEL); + if (!page) { + return -ENOMEM; + } + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * Start up the serial port + */ + + retval = startup(info); + if (retval) + return retval; + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + change_speed(info); + } + + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttyS%d successful...\n", info->line); +#endif + return 0; +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct e100_serial *info) +{ + char stat_buf[30], control, status; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d", + info->line, info->port, info->irq); + + if (!info->port || (info->type == PORT_UNKNOWN)) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (E100_RTS_GET(info)) + strcat(stat_buf, "|RTS"); + if (E100_CTS_GET(info)) + strcat(stat_buf, "|CTS"); + if (E100_DTR_GET(info)) + strcat(stat_buf, "|DTR"); + if (E100_DSR_GET(info)) + strcat(stat_buf, "|DSR"); + if (E100_CD_GET(info)) + strcat(stat_buf, "|CD"); + if (E100_RI_GET(info)) + strcat(stat_buf, "|RI"); + + ret += sprintf(buf+ret, " baud:%d", info->baud); + + ret += sprintf(buf+ret, " tx:%d rx:%d", + info->icount.tx, info->icount.rx); + + if (info->icount.frame) + ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + + if (info->icount.parity) + ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + + if (info->icount.brk) + ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + + if (info->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + return ret; +} + +int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s\n", + serial_version); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &rs_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (off-begin); + return ((count < begin+len-off) ? count : begin+len-off); +} + +/* Finally, routines used to initialize the serial driver. */ + +static void +show_serial_version(void) +{ + printk("ETRAX 100LX serial-driver %s, (c) 2000 Axis Communications AB\r\n", + serial_version); +} + +/* rs_init inits the driver at boot (using the module_init chain) */ + +static int __init +rs_init(void) +{ + int i; + struct e100_serial *info; + + show_serial_version(); + + init_bh(SERIAL_BH, do_serial_bh); + + /* Setup the timed flush handler system */ + + init_timer(&flush_timer); + flush_timer.function = timed_flush_handler; + mod_timer(&flush_timer, jiffies + MAX_FLUSH_TIME); + + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; +#if (LINUX_VERSION_CODE > 0x20100) + serial_driver.driver_name = "serial"; +#endif + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = NR_PORTS; /* etrax100 has 4 serial ports */ + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ + serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + /* should we have an rs_put_char as well here ? */ + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; +#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ + serial_driver.break_ctl = rs_break; +#endif +#if (LINUX_VERSION_CODE >= 131343) + serial_driver.send_xchar = rs_send_xchar; + serial_driver.wait_until_sent = rs_wait_until_sent; + serial_driver.read_proc = rs_read_proc; +#endif + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; +#if (LINUX_VERSION_CODE >= 131343) + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; +#endif + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + + /* do some initializing for the separate ports */ + + for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { + info->line = i; + info->tty = 0; + info->type = PORT_ETRAX100; + info->tr_running = 0; + info->fifo_magic = 0; + info->fifo_didmagic = 0; + info->flags = 0; + info->close_delay = 5*HZ/10; + info->closing_wait = 30*HZ; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->callout_termios = callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + info->xmit.buf = 0; + info->xmit.tail = info->xmit.head = 0; + + printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n", + serial_driver.name, info->line, (unsigned int)info->port); + } + +#ifndef CONFIG_SVINTO_SIM + /* Not needed in simulator. May only complicate stuff. */ + /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ + if(request_irq(22, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL)) + panic("irq22"); + if(request_irq(23, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL)) + panic("irq23"); +#ifdef SERIAL_HANDLE_EARLY_ERRORS + if(request_irq(8, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) + panic("irq8"); +#endif + if(request_irq(24, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL)) + panic("irq24"); + if(request_irq(25, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL)) + panic("irq25"); +#ifdef CONFIG_ETRAX100_SERIAL_PORT2 + /* DMA Shared with par0 (and SCSI0 and ATA) */ + if(request_irq(18, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL)) + panic("irq18"); + if(request_irq(19, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL)) + panic("irq19"); +#endif +#ifdef CONFIG_ETRAX100_SERIAL_PORT3 + /* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */ + if(request_irq(20, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL)) + panic("irq20"); + if(request_irq(21, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL)) + panic("irq21"); +#endif +#ifdef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST + /* TODO: a timeout_interrupt needs to be written that calls timeout_handler */ + if(request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ, + "fast serial dma timeout", NULL)) { + printk("err: timer1 irq\n"); + } +#endif +#endif /* CONFIG_SVINTO_SIM */ + + return 0; +} + +/* this makes sure that rs_init is called during kernel boot */ + +module_init(rs_init); + +/* + * register_serial and unregister_serial allows for serial ports to be + * configured at run-time, to support PCMCIA modems. + */ +int +register_serial(struct serial_struct *req) +{ + return -1; +} + +void unregister_serial(int line) +{ +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/drivers/serial.h linux/arch/cris/drivers/serial.h --- v2.4.1/linux/arch/cris/drivers/serial.h Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/drivers/serial.h Thu Feb 8 16:32:44 2001 @@ -0,0 +1,106 @@ +/* + * serial.h: Arch-dep definitions for the Etrax100 serial driver. + * + * Copyright (C) 1998, 1999, 2000 Axis Communications AB + */ + +#ifndef _ETRAX100_SERIAL_H +#define _ETRAX100_SERIAL_H + +#include +#include +#include + +/* Software state per channel */ + +#ifdef __KERNEL__ +/* + * This is our internal structure for each serial port's state. + * + * Many fields are paralleled by the structure used by the serial_struct + * structure. + * + * For definitions of the flags field, see tty.h + */ + +struct e100_serial { + int baud; + volatile unsigned char * port; /* R_SERIALx_CTRL */ + unsigned long irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ + + volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ + volatile unsigned long *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ + volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ + const volatile unsigned short *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */ + volatile unsigned long *ohwswadr; /* adr to R_DMA_CHx_HWSW, output */ + + volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ + volatile unsigned long *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ + volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ + const volatile unsigned short *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ + volatile unsigned long *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ + + int flags; /* defined in tty.h */ + + unsigned char rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ + unsigned char tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ + unsigned char iseteop; /* bit number for R_SET_EOP for the input dma */ +/* end of fields defined in rs_table[] in .c-file */ + unsigned char fifo_didmagic; /* a fifo eop has been forced */ + + struct etrax_dma_descr tr_descr, rec_descr; + + int fifo_magic; /* fifo amount - bytes left in dma buffer */ + + volatile int tr_running; /* 1 if output is running */ + + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + unsigned long event; + unsigned long last_active; + int line; + int type; /* PORT_ETRAX100 */ + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + struct circ_buf xmit; + + struct tq_struct tqueue; + struct async_icount icount; /* error-statistics etc.*/ + struct termios normal_termios; + struct termios callout_termios; +#ifdef DECLARE_WAITQUEUE + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; +#else + struct wait_queue *open_wait; + struct wait_queue *close_wait; +#endif + +#ifdef CONFIG_RS485 + struct rs485_control rs485; /* RS-485 support */ +#endif +}; + +/* this PORT is not in the standard serial.h. it's not actually used for + * anything since we only have one type of async serial-port anyway in this + * system. + */ + +#define PORT_ETRAX100 1 + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define RS_EVENT_WRITE_WAKEUP 0 + +#endif /* __KERNEL__ */ + +#endif /* !(_ETRAX100_SERIAL_H) */ diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/Makefile linux/arch/cris/kernel/Makefile --- v2.4.1/linux/arch/cris/kernel/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/Makefile Thu Feb 8 16:32:44 2001 @@ -0,0 +1,25 @@ +# $Id: Makefile,v 1.3 2001/01/10 21:11:07 bjornw Exp $ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.o: + $(CC) $(AFLAGS) -traditional -c $< -o $*.o + +all: kernel.o head.o + +O_TARGET := kernel.o +obj-y := process.o signal.o entry.o traps.o irq.o \ + ptrace.o setup.o time.o sys_cris.o shadows.o \ + debugport.o semaphore.o + +obj-$(CONFIG_KGDB) += kgdb.o + +clean: + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/debugport.c linux/arch/cris/kernel/debugport.c --- v2.4.1/linux/arch/cris/kernel/debugport.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/debugport.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,242 @@ +/* Serialport functions for debugging + * + * Copyright (c) 2000 Axis Communications AB + * + * Authors: Bjorn Wesen + * + * Exports: + * console_print_etrax(char *buf) + * int getDebugChar() + * putDebugChar(int) + * enableDebugIRQ() + * init_etrax_debug() + * + * $Log: debugport.c,v $ + * Revision 1.4 2000/10/06 12:37:26 bjornw + * Use physical addresses when talking to DMA + * + * + */ + +#include +#include +#include +#include + +#include +#include +#include /* Get SIMCOUT. */ + +/* Which serial-port is our debug port ? */ + +#if defined(CONFIG_DEBUG_PORT0) || defined(CONFIG_DEBUG_PORT_NULL) +#define DEBUG_PORT_IDX 0 +#define DEBUG_OCMD R_DMA_CH6_CMD +#define DEBUG_FIRST R_DMA_CH6_FIRST +#define DEBUG_OCLRINT R_DMA_CH6_CLR_INTR +#define DEBUG_STATUS R_DMA_CH6_STATUS +#define DEBUG_READ R_SERIAL0_READ +#define DEBUG_WRITE R_SERIAL0_TR_DATA +#define DEBUG_TR_CTRL R_SERIAL0_TR_CTRL +#define DEBUG_REC_CTRL R_SERIAL0_REC_CTRL +#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser0_data, set) +#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma6_descr, clr) +#endif + +#ifdef CONFIG_DEBUG_PORT1 +#define DEBUG_PORT_IDX 1 +#define DEBUG_OCMD R_DMA_CH8_CMD +#define DEBUG_FIRST R_DMA_CH8_FIRST +#define DEBUG_OCLRINT R_DMA_CH8_CLR_INTR +#define DEBUG_STATUS R_DMA_CH8_STATUS +#define DEBUG_READ R_SERIAL1_READ +#define DEBUG_WRITE R_SERIAL1_TR_DATA +#define DEBUG_TR_CTRL R_SERIAL1_TR_CTRL +#define DEBUG_REC_CTRL R_SERIAL1_REC_CTRL +#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser1_data, set) +#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma8_descr, clr) +#endif + +#ifdef CONFIG_DEBUG_PORT2 +#define DEBUG_PORT_IDX 2 +#define DEBUG_OCMD R_DMA_CH2_CMD +#define DEBUG_FIRST R_DMA_CH2_FIRST +#define DEBUG_OCLRINT R_DMA_CH2_CLR_INTR +#define DEBUG_STATUS R_DMA_CH2_STATUS +#define DEBUG_READ R_SERIAL2_READ +#define DEBUG_WRITE R_SERIAL2_TR_DATA +#define DEBUG_TR_CTRL R_SERIAL2_TR_CTRL +#define DEBUG_REC_CTRL R_SERIAL2_REC_CTRL +#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser2_data, set) +#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma2_descr, clr) +#endif + +#ifdef CONFIG_DEBUG_PORT3 +#define DEBUG_PORT_IDX 3 +#define DEBUG_OCMD R_DMA_CH4_CMD +#define DEBUG_FIRST R_DMA_CH4_FIRST +#define DEBUG_OCLRINT R_DMA_CH4_CLR_INTR +#define DEBUG_STATUS R_DMA_CH4_STATUS +#define DEBUG_READ R_SERIAL3_READ +#define DEBUG_WRITE R_SERIAL3_TR_DATA +#define DEBUG_TR_CTRL R_SERIAL3_TR_CTRL +#define DEBUG_REC_CTRL R_SERIAL3_REC_CTRL +#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser3_data, set) +#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma4_descr, clr) +#endif + +/* Write a string of count length to the console (debug port) using DMA, polled + * for completion. Interrupts are disabled during the whole process. Some + * caution needs to be taken to not interfere with ttyS business on this port. + */ + +static void +console_write(struct console *co, const char *buf, unsigned int len) +{ + static struct etrax_dma_descr descr; + unsigned long flags; + int in_progress; + +#ifdef CONFIG_DEBUG_PORT_NULL + /* no debug printout at all */ + return; +#endif + +#ifdef CONFIG_SVINTO_SIM + /* no use to simulate the serial debug output */ + SIMCOUT(buf,len); + return; +#endif + + save_flags(flags); + cli(); + +#ifdef CONFIG_KGDB + /* kgdb needs to output debug info using the gdb protocol */ + putDebugString(buf, len); + restore_flags(flags); + return; +#endif + + /* make sure the transmitter is enabled. + * NOTE: this overrides any setting done in ttySx, to 8N1, no auto-CTS. + * in the future, move the tr/rec_ctrl shadows from etrax100ser.c to + * shadows.c and use it here as well... + */ + + *DEBUG_TR_CTRL = 0x40; + + /* if the tty has some ongoing business, remember it */ + + in_progress = *DEBUG_OCMD & 7; + + if(in_progress) { + /* wait until the output dma channel is ready */ + + while(*DEBUG_OCMD & 7) /* nothing */ ; + } + + descr.ctrl = d_eol; + descr.sw_len = len; + descr.buf = __pa(buf); + + *DEBUG_FIRST = __pa(&descr); /* write to R_DMAx_FIRST */ + *DEBUG_OCMD = 1; /* dma command start -> R_DMAx_CMD */ + + /* wait until the output dma channel is ready again */ + + while(*DEBUG_OCMD & 7) /* nothing */; + + /* clear pending interrupts so we don't get a surprise below */ + + if(in_progress) + *DEBUG_OCLRINT = 2; /* only clear EOP, leave DESCR for the tty */ + else + *DEBUG_OCLRINT = 3; /* clear both EOP and DESCR */ + + while(*DEBUG_STATUS & 0x7f); /* wait until output FIFO is empty as well */ + + restore_flags(flags); +} + +/* legacy function */ + +void +console_print_etrax(const char *buf) +{ + console_write(NULL, buf, strlen(buf)); +} + +/* Use polling to get a single character FROM the debug port */ + +int +getDebugChar(void) +{ + unsigned long readval; + + do { + readval = *DEBUG_READ; + } while(!(readval & IO_MASK(R_SERIAL0_READ, data_avail))); + + return (readval & IO_MASK(R_SERIAL0_READ, data_in)); +} + +/* Use polling to put a single character to the debug port */ + +void +putDebugChar(int val) +{ + while(!(*DEBUG_READ & IO_MASK(R_SERIAL0_READ, tr_ready))) ; +; + *DEBUG_WRITE = val; +} + +/* Enable irq for receiving chars on the debug port, used by kgdb */ + +void +enableDebugIRQ(void) +{ + *R_IRQ_MASK1_SET = DEBUG_IRQ; + /* use R_VECT_MASK directly, since we really bypass Linux normal + * IRQ handling in kgdb anyway, we don't need to use enable_irq + */ + *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set); + + *DEBUG_REC_CTRL = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); +} + +static kdev_t +console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +static int __init +console_setup(struct console *co, char *options) +{ + return 0; +} + +static struct console sercons = { + "ttyS", + console_write, + NULL, + console_device, + NULL, + NULL, + console_setup, + CON_PRINTBUFFER, + DEBUG_PORT_IDX, + 0, + NULL +}; + +/* + * Register console (for printk's etc) + */ + +void __init +init_etrax_debug(void) +{ + register_console(&sercons); +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S --- v2.4.1/linux/arch/cris/kernel/entry.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/entry.S Thu Feb 8 16:32:44 2001 @@ -0,0 +1,738 @@ +/* $Id: entry.S,v 1.11 2001/01/10 21:13:29 bjornw Exp $ + * + * linux/arch/cris/entry.S + * + * Copyright (C) 2000 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * $Log: entry.S,v $ + * Revision 1.11 2001/01/10 21:13:29 bjornw + * SYMBOL_NAME is defined incorrectly for the compiler options we currently use + * + * Revision 1.10 2000/12/18 23:47:56 bjornw + * * Added syscall trace support (ptrace), completely untested of course + * * Removed redundant check for NULL entries in syscall_table + * + * Revision 1.9 2000/11/21 16:40:51 bjornw + * * New frame type used when an SBFS frame needs to be popped without + * actually restarting the instruction + * * Enable interrupts in signal_return (they did so in x86, I hope it's a good + * idea) + * + * Revision 1.8 2000/11/17 16:53:35 bjornw + * Added detection of frame-type in Rexit, so that mmu_bus_fault can + * use ret_from_intr in the return-path to check for signals (like SEGV) + * and other foul things that might have occured during the fault. + * + * Revision 1.7 2000/10/06 15:04:28 bjornw + * Include mof in register savings + * + * Revision 1.6 2000/09/12 16:02:44 bjornw + * Linux-2.4.0-test7 derived updates + * + * Revision 1.5 2000/08/17 15:35:15 bjornw + * 2.4.0-test6 changed local_irq_count and friends API + * + * Revision 1.4 2000/08/02 13:59:30 bjornw + * Removed olduname and uname from the syscall list + * + * Revision 1.3 2000/07/31 13:32:58 bjornw + * * Export ret_from_intr + * * _resume updated (prev/last tjohejsan) + * * timer_interrupt obsolete + * * SIGSEGV detection in mmu_bus_fault temporarily disabled + * + * + */ + +/* + * entry.S contains the system-call and fault low-level handling routines. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + * + * Stack layout in 'ret_from_system_call': + * ptrace needs to have all regs on the stack. + * if the order here is changed, it needs to be + * updated in fork.c:copy_process, signal.c:do_signal, + * ptrace.c and ptrace.h + * + */ + +#include +#include + + ;; functions exported from this file + + .globl _system_call + .globl _ret_from_intr + .globl _ret_from_sys_call + .globl _resume + .globl _multiple_interrupt + .globl _hwbreakpoint + .globl _IRQ1_interrupt + .globl _timer_interrupt + .globl _timer_shortcut + .globl _spurious_interrupt + .globl _hw_bp_trigs + .globl _mmu_bus_fault + + .globl _sys_call_table + + ;; syscall error codes + +LENOSYS = 38 + + ;; offsets into the task_struct (found at sp aligned to THREAD_SIZE, 8192) + ;; linux/sched.h + +LTASK_SIGPENDING = 8 +LTASK_NEEDRESCHED = 20 +LTASK_PTRACE = 24 + + ;; some pt_regs offsets (from ptrace.h) + +LORIG_R10 = 4 +LR13 = 8 +LR12 = 12 +LR11 = 16 +LR10 = 20 +LR1 = 56 +LR0 = 60 +LDCCR = 68 +LSRP = 72 +LIRP = 76 + + ;; below are various parts of system_call which are not in the fast-path + + ;; handle software irqs + +handle_softirq: + push r9 + jsr _do_softirq ; call the C routine for softirq handling + pop r9 + + ;; fall-through + +_ret_from_intr: + ;; check for resched only if we're going back to user-mode + + move ccr, r0 + btstq 8, r0 ; U-flag + bpl Rexit ; go back directly + nop + ba ret_with_reschedule ; go back but check schedule and signals first + nop + +reschedule: + ;; keep r9 intact + push r9 + jsr _schedule + pop r9 + ba _ret_from_sys_call + nop + + ;; return but call do_signal first +signal_return: + ei ; we can get here from an interrupt + move.d r9,r10 ; do_signals syscall/irq param + moveq 0,r11 ; oldset param - 0 in this case + move.d sp,r12 ; another argument to do_signal (the regs param) + jsr _do_signal ; arch/cris/kernel/signal.c + ba Rexit + nop + + ;; The system_call is called by a BREAK instruction, which works like + ;; an interrupt call but it stores the return PC in BRP instead of IRP. + ;; Since we dont really want to have two epilogues (one for system calls + ;; and one for interrupts) we push the contents of BRP instead of IRP in the + ;; system call prologue, to make it look like an ordinary interrupt on the + ;; stackframe. + ;; + ;; Since we can't have system calls inside interrupts, it should not matter + ;; that we don't stack IRP. + ;; + ;; In r1 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,r0 + ;; + ;; This function looks on the _surface_ like spaghetti programming, but it's + ;; really designed so that the fast-path does not force cache-loading of non-used + ;; instructions. Only the non-common cases cause the outlined code to run.. + +_system_call: + ;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call + push brp ; this is normally push irp + push srp + push dccr + push mof + subq 14*4,sp ; make room for r0-r13 + movem r13,[sp] ; push r0-r13 + push r10 ; push orig_r10 + clear.d [sp=sp-4] ; frametype == 0, normal stackframe + + move.d r10,r2 ; save for later + + movs.w -LENOSYS,r10 + move.d r10,[sp+LR10] ; put the default return value in r10 in the frame + + move.d sp,r10 + jsr _set_esp0 ; save top of frame (clobbers r9...) + + ;; check if this process is syscall-traced + + move.d sp, r10 + and.d -8192, r10 ; THREAD_SIZE == 8192 + move.d [r10+LTASK_PTRACE],r10 + btstq 2, r10 ; PT_TRACESYS + bmi tracesys + nop + + ;; check for sanity in the requested syscall number + + cmpu.w NR_syscalls,r1 + bcc _ret_from_sys_call + lslq 2,r1 ; multiply by 4, in the delay slot + + ;; read the system call vector into r1 + + move.d [r1+_sys_call_table],r1 + + ;; the parameter carrying registers r11, r12 and 13 are intact - restore r10. + ;; the fifth parameter (if any) was in r0, and we need to put it on the stack + + push r0 + move.d r2,r10 + + jsr r1 ; actually call the corresponding system call + addq 4,sp ; pop the r0 parameter + move.d r10,[sp+LR10] ; save the return value + + moveq 1,r9 ; "parameter" to ret_from_sys_call to show it was a sys call + + ;; fall through into ret_from_sys_call to return + +_ret_from_sys_call: + ;; r9 is a parameter - if 1, we came from a syscall, if 0, from an irq + + ;; check if any bottom halves need service + + move.d [_irq_stat],r0 ; softirq_active + and.d [_irq_stat+4],r0 ; softirq_mask + bne handle_softirq + nop + +ret_with_reschedule: + ;; first get the current task-struct pointer (see top for defs) + + move.d sp, r0 + and.d -8192, r0 ; THREAD_SIZE == 8192 + + ;; see if we want to reschedule into another process + + test.d [r0+LTASK_NEEDRESCHED] + bne reschedule + nop + + ;; see if we need to run signal checks (important that r9 is intact here) + + test.d [r0+LTASK_SIGPENDING] + bne signal_return + nop + +Rexit: + ;; this epilogue MUST match the prologues in multiple_interrupt, irq.h and ptregs.h + pop r10 ; frametype + bne RBFexit ; was not CRIS_FRAME_NORMAL, handle otherwise + addq 4,sp ; skip orig_r10, in delayslot + movem [sp+],r13 ; registers r0-r13 + pop mof ; multiply overflow register + pop dccr ; condition codes + pop srp ; subroutine return pointer + jmpu [sp+] ; return by popping irp and jumping there + ;; jmpu takes the U-flag into account to see if we return to + ;; user-mode or kernel mode. + +RBFexit: + cmpq 2, r10 ; was it CRIS_FRAME_FIXUP ? + beq 2f + movem [sp+],r13 ; registers r0-r13, in delay slot + pop mof ; multiply overflow register + pop dccr ; condition codes + pop srp ; subroutine return pointer + rbf [sp+] ; return by popping the CPU status + +2: pop mof ; multiply overflow register + pop dccr ; condition codes + pop srp ; subroutine return pointer + ;; now we have a 4-word SBFS frame which we do not want to restore + ;; using RBF since we have made a fixup. instead we would like to + ;; just get the PC value to restart it with, and skip the rest of + ;; the frame. + pop irp ; fixup location will be here + pop p8 ; null pop + pop p8 ; null pop + reti ; return to IRP, taking U-flag into account + pop p8 ; null pop in delayslot + + +tracesys: + ;; this first invocation of syscall_trace _requires_ that + ;; LR10 in the frame contains -LENOSYS (as is set in the beginning + ;; of system_call + + jsr _syscall_trace + + ;; now we should more or less do the same things as in the system_call + ;; but since our argument regs got clobbered during syscall_trace and + ;; because syscall_trace might want to alter them, we need to reload them + ;; from the stack-frame as we use them. + + ;; check for sanity in the requested syscall number + + move.d [sp+LR1], r1 + movs.w -LENOSYS, r10 + cmpu.w NR_syscalls,r1 + bcc 1f + lslq 2,r1 ; multiply by 4, in the delay slot + + ;; read the system call vector entry into r1 + + move.d [r1+_sys_call_table],r1 + + ;; restore r10, r11, r12, r13 and r0 into the needed registers + + move.d [sp+LORIG_R10], r10 ; LR10 is already filled with -LENOSYS + move.d [sp+LR11], r11 + move.d [sp+LR12], r12 + move.d [sp+LR13], r13 + move.d [sp+LR0], r0 + + ;; the fifth parameter needs to be put on the stack for the system + ;; call to find it + + push r0 + jsr r1 ; actually call the system-call + addq 4,sp ; pop the r0 parameter + +1: move.d r10,[sp+LR10] ; save the return value + + ;; second call of syscall_trace, to let it grab the results + + jsr _syscall_trace + + moveq 1,r9 ; "parameter" to ret_from_sys_call to show it was a sys call + ba _ret_from_sys_call + nop + + ;; from asm/processor.h, the thread_struct + +LTHREAD_KSP = 0 +LTHREAD_USP = 4 +LTHREAD_ESP0 = 8 +LTHREAD_DCCR = 12 + + ;; _resume performs the actual task-switching, by switching stack pointers + ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct + ;; returns old current in r10 + ;; + ;; TODO: see the i386 version. The switch_to which calls resume in our version + ;; could really be an inline asm of this. + +_resume: + push srp ; we keep the old/new PC on the stack + add.d r12, r10 ; r10 = current tasks tss + move dccr, [r10+LTHREAD_DCCR] ; save irq enable state + di + + move usp, [r10+LTHREAD_USP] ; save user-mode stackpointer + + subq 10*4, sp + movem r9, [sp] ; save non-scratch registers + + move.d sp, [r10+LTHREAD_KSP] ; save the kernel stack pointer for the old task + move.d sp, r10 ; return last running task in r10 + and.d -8192, r10 ; get task ptr from stackpointer + add.d r12, r11 ; find the new tasks tss + move.d [r11+LTHREAD_KSP], sp ; switch into the new stackframe by restoring kernel sp + + movem [sp+], r9 ; restore non-scratch registers + + move [r11+LTHREAD_USP], usp ; restore user-mode stackpointer + + move [r11+LTHREAD_DCCR], dccr ; restore irq enable status + jump [sp+] ; restore PC + + ;; This is the MMU bus fault handler. + ;; It needs to stack the CPU status and overall is different + ;; from the other interrupt handlers. + +_mmu_bus_fault: + sbfs [sp=sp-16] ; push the internal CPU status + ;; the first longword in the sbfs frame was the interrupted PC + ;; which fits nicely with the "IRP" slot in pt_regs normally used to + ;; contain the return address. used by Oops to print kernel errors.. + push srp ; make a stackframe similar to pt_regs + push dccr + push mof + di + subq 14*4, sp + movem r13, [sp] + push r10 ; dummy orig_r10 + moveq 1, r10 + push r10 ; frametype == 1, BUSFAULT frame type + + moveq 0, r9 ; busfault is equivalent to an irq + + move.d sp, r10 ; pt_regs argument to handle_mmu_bus_fault + + jsr _handle_mmu_bus_fault ; in arch/cris/mm/fault.c + + ;; now we need to return through the normal path, we cannot just + ;; do the RBFexit since we might have killed off the running + ;; process due to a SEGV, scheduled due to a page blocking or + ;; whatever. + + ba _ret_from_intr + nop + + ;; special handlers for breakpoint and NMI +#if 0 +_hwbreakpoint: + push dccr + di + push r10 + push r11 + push r12 + push r13 + clearf b + move brp,r11 + move.d [_hw_bp_msg],r10 + jsr _printk + setf b + pop r13 + pop r12 + pop r11 + pop r10 + pop dccr + retb + nop +#else +_hwbreakpoint: + push dccr + di +#if 1 + push r10 + push r11 + move.d [_hw_bp_trig_ptr],r10 + move.d [r10],r11 + cmp.d 42,r11 + beq nobp + nop + move brp,r11 + move.d r11,[r10+] + move.d r10,[_hw_bp_trig_ptr] +nobp: pop r11 + pop r10 +#endif + pop dccr + retb + nop +#endif + +_IRQ1_interrupt: +_spurious_interrupt: + di + move.b 4,r0 + move.b r0,[0xb0000030] +basse2: ba basse2 + nop + + ;; this handles the case when multiple interrupts arrive at the same time + ;; we jump to the first set interrupt bit in a priority fashion + ;; the hardware will call the unserved interrupts after the handler finishes + +_multiple_interrupt: + ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! + push irp + push srp + push dccr + push mof + di + subq 14*4,sp + movem r13,[sp] + push r10 ; push orig_r10 + clear.d [sp=sp-4] ; frametype == 0, normal frame + + move.d _irq_shortcuts + 8,r1 + moveq 2,r2 ; first bit we care about is the timer0 irq + move.d [0xb00000d8],r0 ; read the irq bits that triggered the multiple irq +multloop: + btst r2,r0 ; check for the irq given by bit r2 + bmi do_shortcut ; actually do the shortcut + nop + addq 1,r2 ; next vector bit - remember this is in the delay slot! + addq 4,r1 ; next vector + cmpq 26,r2 + bne multloop ; process all irq's up to and including number 25 + nop + + ;; strange, we didn't get any set vector bits.. oh well, just return + + ba Rexit + nop + +do_shortcut: + test.d [r1] + beq Rexit + nop + jump [r1] ; jump to the irq handlers shortcut + + + .data + +_hw_bp_trigs: + .space 64*4 +_hw_bp_trig_ptr: + .dword _hw_bp_trigs + +/* linux/linkage.h got it wrong for this compiler currently */ + +#undef SYMBOL_NAME +#define SYMBOL_NAME(X) _/**/X + +_sys_call_table: + .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/ + .long SYMBOL_NAME(sys_exit) + .long SYMBOL_NAME(sys_fork) + .long SYMBOL_NAME(sys_read) + .long SYMBOL_NAME(sys_write) + .long SYMBOL_NAME(sys_open) /* 5 */ + .long SYMBOL_NAME(sys_close) + .long SYMBOL_NAME(sys_waitpid) + .long SYMBOL_NAME(sys_creat) + .long SYMBOL_NAME(sys_link) + .long SYMBOL_NAME(sys_unlink) /* 10 */ + .long SYMBOL_NAME(sys_execve) + .long SYMBOL_NAME(sys_chdir) + .long SYMBOL_NAME(sys_time) + .long SYMBOL_NAME(sys_mknod) + .long SYMBOL_NAME(sys_chmod) /* 15 */ + .long SYMBOL_NAME(sys_lchown16) + .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ + .long SYMBOL_NAME(sys_stat) + .long SYMBOL_NAME(sys_lseek) + .long SYMBOL_NAME(sys_getpid) /* 20 */ + .long SYMBOL_NAME(sys_mount) + .long SYMBOL_NAME(sys_oldumount) + .long SYMBOL_NAME(sys_setuid16) + .long SYMBOL_NAME(sys_getuid16) + .long SYMBOL_NAME(sys_stime) /* 25 */ + .long SYMBOL_NAME(sys_ptrace) + .long SYMBOL_NAME(sys_alarm) + .long SYMBOL_NAME(sys_fstat) + .long SYMBOL_NAME(sys_pause) + .long SYMBOL_NAME(sys_utime) /* 30 */ + .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */ + .long SYMBOL_NAME(sys_access) + .long SYMBOL_NAME(sys_nice) + .long SYMBOL_NAME(sys_ni_syscall) /* 35 old ftime syscall holder */ + .long SYMBOL_NAME(sys_sync) + .long SYMBOL_NAME(sys_kill) + .long SYMBOL_NAME(sys_rename) + .long SYMBOL_NAME(sys_mkdir) + .long SYMBOL_NAME(sys_rmdir) /* 40 */ + .long SYMBOL_NAME(sys_dup) + .long SYMBOL_NAME(sys_pipe) + .long SYMBOL_NAME(sys_times) + .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ + .long SYMBOL_NAME(sys_brk) /* 45 */ + .long SYMBOL_NAME(sys_setgid16) + .long SYMBOL_NAME(sys_getgid16) + .long SYMBOL_NAME(sys_signal) + .long SYMBOL_NAME(sys_geteuid16) + .long SYMBOL_NAME(sys_getegid16) /* 50 */ + .long SYMBOL_NAME(sys_acct) + .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ + .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ + .long SYMBOL_NAME(sys_ioctl) + .long SYMBOL_NAME(sys_fcntl) /* 55 */ + .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */ + .long SYMBOL_NAME(sys_setpgid) + .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old sys_olduname holder */ + .long SYMBOL_NAME(sys_umask) /* 60 */ + .long SYMBOL_NAME(sys_chroot) + .long SYMBOL_NAME(sys_ustat) + .long SYMBOL_NAME(sys_dup2) + .long SYMBOL_NAME(sys_getppid) + .long SYMBOL_NAME(sys_getpgrp) /* 65 */ + .long SYMBOL_NAME(sys_setsid) + .long SYMBOL_NAME(sys_sigaction) + .long SYMBOL_NAME(sys_sgetmask) + .long SYMBOL_NAME(sys_ssetmask) + .long SYMBOL_NAME(sys_setreuid16) /* 70 */ + .long SYMBOL_NAME(sys_setregid16) + .long SYMBOL_NAME(sys_sigsuspend) + .long SYMBOL_NAME(sys_sigpending) + .long SYMBOL_NAME(sys_sethostname) + .long SYMBOL_NAME(sys_setrlimit) /* 75 */ + .long SYMBOL_NAME(sys_old_getrlimit) + .long SYMBOL_NAME(sys_getrusage) + .long SYMBOL_NAME(sys_gettimeofday) + .long SYMBOL_NAME(sys_settimeofday) + .long SYMBOL_NAME(sys_getgroups16) /* 80 */ + .long SYMBOL_NAME(sys_setgroups16) + .long SYMBOL_NAME(sys_select) /* was old_select in Linux/E100 */ + .long SYMBOL_NAME(sys_symlink) + .long SYMBOL_NAME(sys_lstat) + .long SYMBOL_NAME(sys_readlink) /* 85 */ + .long SYMBOL_NAME(sys_uselib) + .long SYMBOL_NAME(sys_swapon) + .long SYMBOL_NAME(sys_reboot) + .long SYMBOL_NAME(old_readdir) + .long SYMBOL_NAME(old_mmap) /* 90 */ + .long SYMBOL_NAME(sys_munmap) + .long SYMBOL_NAME(sys_truncate) + .long SYMBOL_NAME(sys_ftruncate) + .long SYMBOL_NAME(sys_fchmod) + .long SYMBOL_NAME(sys_fchown16) /* 95 */ + .long SYMBOL_NAME(sys_getpriority) + .long SYMBOL_NAME(sys_setpriority) + .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ + .long SYMBOL_NAME(sys_statfs) + .long SYMBOL_NAME(sys_fstatfs) /* 100 */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_ioperm in i386 */ + .long SYMBOL_NAME(sys_socketcall) + .long SYMBOL_NAME(sys_syslog) + .long SYMBOL_NAME(sys_setitimer) + .long SYMBOL_NAME(sys_getitimer) /* 105 */ + .long SYMBOL_NAME(sys_newstat) + .long SYMBOL_NAME(sys_newlstat) + .long SYMBOL_NAME(sys_newfstat) + .long SYMBOL_NAME(sys_ni_syscall) /* old sys_uname holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_iopl in i386 */ + .long SYMBOL_NAME(sys_vhangup) + .long SYMBOL_NAME(sys_ni_syscall) /* old "idle" system call */ + .long SYMBOL_NAME(sys_ni_syscall) /* vm86old in i386 */ + .long SYMBOL_NAME(sys_wait4) + .long SYMBOL_NAME(sys_swapoff) /* 115 */ + .long SYMBOL_NAME(sys_sysinfo) + .long SYMBOL_NAME(sys_ipc) + .long SYMBOL_NAME(sys_fsync) + .long SYMBOL_NAME(sys_sigreturn) + .long SYMBOL_NAME(sys_clone) /* 120 */ + .long SYMBOL_NAME(sys_setdomainname) + .long SYMBOL_NAME(sys_newuname) + .long SYMBOL_NAME(sys_ni_syscall) /* TODO sys_modify_ldt - do something ?*/ + .long SYMBOL_NAME(sys_adjtimex) + .long SYMBOL_NAME(sys_mprotect) /* 125 */ + .long SYMBOL_NAME(sys_sigprocmask) + .long SYMBOL_NAME(sys_create_module) + .long SYMBOL_NAME(sys_init_module) + .long SYMBOL_NAME(sys_delete_module) + .long SYMBOL_NAME(sys_get_kernel_syms) /* 130 */ + .long SYMBOL_NAME(sys_quotactl) + .long SYMBOL_NAME(sys_getpgid) + .long SYMBOL_NAME(sys_fchdir) + .long SYMBOL_NAME(sys_bdflush) + .long SYMBOL_NAME(sys_sysfs) /* 135 */ + .long SYMBOL_NAME(sys_personality) + .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */ + .long SYMBOL_NAME(sys_setfsuid16) + .long SYMBOL_NAME(sys_setfsgid16) + .long SYMBOL_NAME(sys_llseek) /* 140 */ + .long SYMBOL_NAME(sys_getdents) + .long SYMBOL_NAME(sys_select) + .long SYMBOL_NAME(sys_flock) + .long SYMBOL_NAME(sys_msync) + .long SYMBOL_NAME(sys_readv) /* 145 */ + .long SYMBOL_NAME(sys_writev) + .long SYMBOL_NAME(sys_getsid) + .long SYMBOL_NAME(sys_fdatasync) + .long SYMBOL_NAME(sys_sysctl) + .long SYMBOL_NAME(sys_mlock) /* 150 */ + .long SYMBOL_NAME(sys_munlock) + .long SYMBOL_NAME(sys_mlockall) + .long SYMBOL_NAME(sys_munlockall) + .long SYMBOL_NAME(sys_sched_setparam) + .long SYMBOL_NAME(sys_sched_getparam) /* 155 */ + .long SYMBOL_NAME(sys_sched_setscheduler) + .long SYMBOL_NAME(sys_sched_getscheduler) + .long SYMBOL_NAME(sys_sched_yield) + .long SYMBOL_NAME(sys_sched_get_priority_max) + .long SYMBOL_NAME(sys_sched_get_priority_min) /* 160 */ + .long SYMBOL_NAME(sys_sched_rr_get_interval) + .long SYMBOL_NAME(sys_nanosleep) + .long SYMBOL_NAME(sys_mremap) + .long SYMBOL_NAME(sys_setresuid16) + .long SYMBOL_NAME(sys_getresuid16) /* 165 */ + .long SYMBOL_NAME(sys_ni_syscall) /* sys_vm86 */ + .long SYMBOL_NAME(sys_query_module) + .long SYMBOL_NAME(sys_poll) + .long SYMBOL_NAME(sys_nfsservctl) + .long SYMBOL_NAME(sys_setresgid16) /* 170 */ + .long SYMBOL_NAME(sys_getresgid16) + .long SYMBOL_NAME(sys_prctl) + .long SYMBOL_NAME(sys_rt_sigreturn) + .long SYMBOL_NAME(sys_rt_sigaction) + .long SYMBOL_NAME(sys_rt_sigprocmask) /* 175 */ + .long SYMBOL_NAME(sys_rt_sigpending) + .long SYMBOL_NAME(sys_rt_sigtimedwait) + .long SYMBOL_NAME(sys_rt_sigqueueinfo) + .long SYMBOL_NAME(sys_rt_sigsuspend) + .long SYMBOL_NAME(sys_pread) /* 180 */ + .long SYMBOL_NAME(sys_pwrite) + .long SYMBOL_NAME(sys_chown16) + .long SYMBOL_NAME(sys_getcwd) + .long SYMBOL_NAME(sys_capget) + .long SYMBOL_NAME(sys_capset) /* 185 */ + .long SYMBOL_NAME(sys_sigaltstack) + .long SYMBOL_NAME(sys_sendfile) + .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ + .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ + .long SYMBOL_NAME(sys_vfork) /* 190 */ + .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_mmap2) + .long SYMBOL_NAME(sys_truncate64) + .long SYMBOL_NAME(sys_ftruncate64) + .long SYMBOL_NAME(sys_stat64) /* 195 */ + .long SYMBOL_NAME(sys_lstat64) + .long SYMBOL_NAME(sys_fstat64) + .long SYMBOL_NAME(sys_lchown) + .long SYMBOL_NAME(sys_getuid) + .long SYMBOL_NAME(sys_getgid) /* 200 */ + .long SYMBOL_NAME(sys_geteuid) + .long SYMBOL_NAME(sys_getegid) + .long SYMBOL_NAME(sys_setreuid) + .long SYMBOL_NAME(sys_setregid) + .long SYMBOL_NAME(sys_getgroups) /* 205 */ + .long SYMBOL_NAME(sys_setgroups) + .long SYMBOL_NAME(sys_fchown) + .long SYMBOL_NAME(sys_setresuid) + .long SYMBOL_NAME(sys_getresuid) + .long SYMBOL_NAME(sys_setresgid) /* 210 */ + .long SYMBOL_NAME(sys_getresgid) + .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_setuid) + .long SYMBOL_NAME(sys_setgid) + .long SYMBOL_NAME(sys_setfsuid) /* 215 */ + .long SYMBOL_NAME(sys_setfsgid) + .long SYMBOL_NAME(sys_pivot_root) + .long SYMBOL_NAME(sys_mincore) + .long SYMBOL_NAME(sys_madvise) + .long SYMBOL_NAME(sys_getdents64) /* 220 */ + + /* + * NOTE!! This doesn't have to be exact - we just have + * to make sure we have _enough_ of the "sys_ni_syscall" + * entries. Don't panic if you notice that this hasn't + * been shrunk every time we add a new system call. + */ + + ;; TODO: this needs to actually generate sys_ni_syscall entires + ;; since we now have removed the check for NULL entries in this + ;; table in system_call! + + .space (NR_syscalls-220)*4 + diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S --- v2.4.1/linux/arch/cris/kernel/head.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/head.S Thu Feb 8 16:32:44 2001 @@ -0,0 +1,519 @@ + ;; $Id: head.S,v 1.11 2001/01/16 16:31:38 bjornw Exp $ + ;; + ;; Head of the kernel - alter with care + ;; + ;; Copyright (C) 2000, 2001 Axis Communications AB + ;; + ;; Authors: Bjorn Wesen (bjornw@axis.com) + ;; + ;; $Log: head.S,v $ + ;; Revision 1.11 2001/01/16 16:31:38 bjornw + ;; * Changed name and semantics of running_from_flash to romfs_in_flash, + ;; set by head.S to indicate to setup.c whether there is a cramfs image + ;; after the kernels BSS or not. Should work for all three boot-cases + ;; (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot), + ;; and flash with cramfs in flash) + ;; + ;; Revision 1.10 2001/01/16 14:12:21 bjornw + ;; * Check for cramfs start passed in r9 from the decompressor, if all other + ;; cramfs options fail (if we boot from DRAM but don't find a cramfs image + ;; after the kernel in DRAM, it is probably still in the flash) + ;; * Check magic in cramfs detection when booting from flash directly + ;; + ;; Revision 1.9 2001/01/15 17:17:02 bjornw + ;; * Corrected the code that detects the cramfs lengths + ;; * Added a comment saying that the above does not work due to other + ;; reasons.. + ;; + ;; Revision 1.8 2001/01/15 16:27:51 jonashg + ;; Made boot after flashing work. + ;; * end destination is __vmlinux_end in RAM. + ;; * _romfs_start moved because of virtual memory. + ;; + ;; Revision 1.7 2000/11/21 13:55:29 bjornw + ;; Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type + ;; + ;; Revision 1.6 2000/10/06 12:36:55 bjornw + ;; Forgot swapper_pg_dir when changing memory map.. + ;; + ;; Revision 1.5 2000/10/04 16:49:30 bjornw + ;; * Fixed memory mapping in LX + ;; * Check for cramfs instead of romfs + ;; + ;; + +#include +#define ASSEMBLER_MACROS_ONLY +#include + +#define CRAMFS_MAGIC 0x28cd3d45 + + ;; exported symbols + + .globl _etrax_irv + .globl _romfs_start + .globl _romfs_length + .globl _romfs_in_flash + .globl _swapper_pg_dir + + .text + + ;; This is the entry point of the kernel. We are in supervisor mode. + ;; 0x00000000 if Flash, 0x40004000 if DRAM + ;; since etrax actually starts at address 2 when booting from flash, we + ;; put a nop (2 bytes) here first so we dont accidentally skip the di + ;; + ;; NOTICE! The register r9 is used as a parameter carrying register from + ;; the decompressor (if the kernel was compressed). It should not be + ;; used in the code below until it is read. + + nop + di + + ;; First setup the kseg_c mapping from where the kernel is linked + ;; to 0x40000000 (where the actual DRAM resides) otherwise + ;; we cannot do very much! See arch/cris/README.mm + ;; + ;; Notice that since we're potentially running at 0x00 or 0x40 right now, + ;; we will get a fault as soon as we enable the MMU if we dont + ;; temporarily map those segments linearily. + ;; + ;; Due to a bug in Etrax-100 LX version 1 we need to map the memory + ;; slightly different. We also let the simulator get this mapping for now. + +#ifdef CONFIG_CRIS_LOW_MAP + move.d 0x0800b000, r0 ; kseg mappings + move.d r0, [R_MMU_KBASE_HI] + + move.d 0x04040000, r0 ; temporary map of 0x40->0x40 and 0x00->0x00 + move.d r0, [R_MMU_KBASE_LO] + + move.d 0x80074871, r0 ; mmu enable, segs e,b,6,5,4,0 segment mapped + move.d r0, [R_MMU_CONFIG] +#else + move.d 0x0804b000, r0 ; kseg mappings + move.d r0, [R_MMU_KBASE_HI] + + move.d 0x00040000, r0 ; temporary map of 0x40->0x40 and 0x00->0x00 + move.d r0, [R_MMU_KBASE_LO] + + move.d 0x8007d811, r0 ; mmu enable, segs f,e,c,b,4,0 segment mapped + move.d r0, [R_MMU_CONFIG] +#endif + + ;; Now we need to sort out the segments and their locations in RAM or + ;; Flash. The image in the Flash (or in DRAM) consists of 3 pieces: + ;; 1) kernel text, 2) kernel data, 3) ROM filesystem image + ;; But the linker has linked the kernel to expect this layout in + ;; DRAM memory: + ;; 1) kernel text, 2) kernel data, 3) kernel BSS + ;; (the location of the ROM filesystem is determined by the krom driver) + ;; If we boot this from Flash, we want to keep the ROM filesystem in + ;; the flash, we want to copy the text and need to copy the data to DRAM. + ;; But if we boot from DRAM, we need to move the ROMFS image + ;; from its position after kernel data, to after kernel BSS, BEFORE the + ;; kernel starts using the BSS area (since its "overlayed" with the ROMFS) + ;; + ;; In both cases, we start in un-cached mode, and need to jump into a + ;; cached PC after we're done fiddling around with the segments. + ;; + ;; arch/etrax100/etrax100.ld sets some symbols that define the start + ;; and end of each segment. + + ;; Check if we start from DRAM or FLASH by testing PC + + move.d pc,r0 + and.d 0x7fffffff,r0 ; get rid of the non-cache bit + cmp.d 0x10000,r0 ; arbitrary... just something above this code + bcs inflash + nop + + jump inram ; enter cached ram + +inflash: + +#ifndef CONFIG_SVINTO_SIM + + ;; We need to setup the bus registers before we start using the DRAM + + move.d DEF_R_WAITSTATES, r0 + move.d r0, [R_WAITSTATES] + + move.d DEF_R_BUS_CONFIG, r0 + move.d r0, [R_BUS_CONFIG] + + move.d DEF_R_DRAM_CONFIG, r0 + move.d r0, [R_DRAM_CONFIG] + + move.d DEF_R_DRAM_TIMING, r0 + move.d r0, [R_DRAM_TIMING] + +#endif + ;; Copy text+data to DRAM + ;; This is fragile - the calculation of r4 as the image size depends + ;; on that the labels below actually are the first and last positions + ;; in the linker-script. + ;; + ;; Then the locating of the cramfs image depends on the aforementioned + ;; image being located in the flash at 0. This is most often not true, + ;; thus the following does not work (normally there is a rescue-block + ;; between the physical start of the flash and the flash-image start, + ;; and when run with compression, the kernel is actually unpacked to + ;; DRAM and we never get here in the first place :)) + + moveq 0, r0 ; source + move.d _text_start, r1 ; destination + move.d __vmlinux_end, r2 ; end destination + move.d r2, r4 + sub.d r1, r4 ; r4=__vmlinux_end in flash, used below +1: move.w [r0+], r3 + move.w r3, [r1+] + cmp.d r2, r1 + bcs 1b + nop + + ;; We keep the cramfs in the flash. + ;; There might be none, but that does not matter because + ;; we don't do anything than read some bytes here. + + moveq 0, r0 + move.d r0, [_romfs_length] ; default if there is no cramfs + + move.d [r4], r0 ; cramfs_super.magic + cmp.d CRAMFS_MAGIC, r0 + bne 1f + nop + move.d [r4 + 4], r0 ; cramfs_super.size + move.d r0, [_romfs_length] +#ifdef CONFIG_CRIS_LOW_MAP + add.d 0x50000000, r4 ; add flash start in virtual memory (cached) +#else + add.d 0xf0000000, r4 ; add flash start in virtual memory (cached) +#endif + move.d r4, [_romfs_start] +1: + moveq 1, r0 + move.d r0, [_romfs_in_flash] + + jump start_it ; enter code, cached this time + +inram: + ;; Move the ROM fs to after BSS end. This assumes that the cramfs + ;; second longword contains the length of the cramfs + + moveq 0, r0 + move.d r0, [_romfs_length] ; default if there is no cramfs + + ;; First check if there is a cramfs (magic value) + ;; Notice that we check for cramfs magic value - which is + ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does + ;; not need this mechanism anyway) + + move.d __vmlinux_end, r0 ; the image will be after the vmlinux end address + move.d [r0], r1 ; cramfs assumes same endian on host/target + cmp.d CRAMFS_MAGIC, r1; magic value in cramfs superblock + bne no_romfs_in_ram + nop + + ;; Ok. What is its size ? + + move.d [r0 + 4], r2 ; cramfs_super.size (again, no need to swapwb) + + ;; We want to copy it to the end of the BSS + + move.d _end, r1 + + ;; Remember values so cramfs and setup can find this info + + move.d r1, [_romfs_start] ; new romfs location + move.d r2, [_romfs_length] + + ;; We need to copy it backwards, since they can be overlapping + + add.d r2, r0 + add.d r2, r1 + + ;; Go ahead. Make my loop. + + lsrq 1, r2 ; size is in bytes, we copy words + +1: move.w [r0=r0-2],r3 + move.w r3,[r1=r1-2] + subq 1, r2 + bne 1b + nop + + ;; Dont worry that the BSS is tainted. It will be cleared later. + + moveq 0, r0 + move.d r0, [_romfs_in_flash] + + jump start_it ; better skip the additional cramfs check below + +no_romfs_in_ram: + + ;; We have still one other possibility at this point - the kernel + ;; could have been unpacked to DRAM by the loader, but the cramfs + ;; image was still in the Flash directly after the compressed kernel + ;; image. The loader passes the address of the byte succeeding the + ;; last compressed byte in the flash in the register r9 when starting + ;; the kernel. Check if r9 points to a decent cramfs image! + ;; (Notice that if this is not booted from the loader, r9 will be + ;; garbage but we do sanity checks on it, the chance that it points + ;; to a cramfs magic is small.. ) + + cmp.d 0x0ffffff8, r9 + bcc 1f ; r9 points outside the flash area + nop + move.d [r9], r0 ; cramfs_super.magic + cmp.d CRAMFS_MAGIC, r0 + bne 1f + nop + move.d [r9+4], r0 ; cramfs_super.length + move.d r0, [_romfs_length] +#ifdef CONFIG_CRIS_LOW_MAP + add.d 0x50000000, r9 ; add flash start in virtual memory (cached) +#else + add.d 0xf0000000, r9 ; add flash start in virtual memory (cached) +#endif + move.d r9, [_romfs_start] + + moveq 1, r0 + move.d r0, [_romfs_in_flash] +1: + + jump start_it ; enter code, cached this time + +start_it: + ;; the kernel stack is overlayed with the task structure for each + ;; task. thus the initial kernel stack is in the same page as the + ;; init_task (but starts in the top of the page, size 8192) + move.d _init_task_union + 8192,sp + move.d _ibr_start,r0 ; this symbol is set by the linker script + move r0,ibr + move.d r0,[_etrax_irv] ; set the interrupt base register and pointer + + ;; Clear BSS region, from _bss_start to _end + + move.d __bss_start, r0 + move.d _end, r1 +1: clear.d [r0+] + cmp.d r1, r0 + bcs 1b + nop + +#ifdef CONFIG_BLK_DEV_ETRAXIDE + ;; disable ATA before enabling it in genconfig below + moveq 0,r0 + move.d r0,[R_ATA_CTRL_DATA] + move.d r0,[R_ATA_TRANSFER_CNT] + move.d r0,[R_ATA_CONFIG] +#if 0 + move.d R_PORT_G_DATA,r1 + move.d r0,[r1]; assert ATA bus-reset + nop + nop + nop + nop + nop + nop + move.d 0x08000000,r0 + move.d r0,[r1] +#endif +#endif + +#ifdef CONFIG_JULIETTE + ;; configure external DMA channel 0 before enabling it in genconfig + + moveq 0,r0 + move.d r0,[R_EXT_DMA_0_ADDR] + move.d 0x860000,r0 ; cnt enable, word size, output, stop, size 0 + move.d r0,[R_EXT_DMA_0_CMD] + + ;; reset dma4 and wait for completion + + moveq 4,r0 + move.b r0,[R_DMA_CH4_CMD] +w4u: move.b [R_DMA_CH4_CMD],r0 + and.b 7,r0 + cmp.b 4,r0 + beq w4u + nop + + ;; reset dma5 and wait for completion + + moveq 4,r0 + move.b r0,[R_DMA_CH5_CMD] +w5u: move.b [R_DMA_CH5_CMD],r0 + and.b 7,r0 + cmp.b 4,r0 + beq w5u + nop +#endif + + ;; Etrax product HW genconfig setup + + moveq 0,r0 +#if !defined(CONFIG_KGDB) && !defined(CONFIG_DMA_MEMCPY) + or.d 0x140000,r0 ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA +#endif +#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1) + or.d 0xc00000,r0 ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA +#endif +#ifdef CONFIG_DMA_MEMCPY + or.d 0x003c0000,r0 ; 6/7 memory-memory DMA +#endif +#ifdef CONFIG_ETRAX100_SERIAL_PORT2 + or.d 0x2808,r0 ; DMA channels 2 and 3 to serport 2, port 2 enabled +#endif +#ifdef CONFIG_ETRAX100_SERIAL_PORT3 + or.d 0x28100,r0 ; DMA channels 4 and 5 to serport 3, port 3 enabled +#endif +#if defined(CONFIG_ETRAX100_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) + or.w 0x4,r0 ; parport 0 enabled using DMA 2/3 +#endif +#if defined(CONFIG_ETRAX100_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) + or.w 0x80,r0 ; parport 1 enabled using DMA 4/5 +#endif +#ifdef CONFIG_BLK_DEV_ETRAXIDE + or.d 0x3c02,r0 ; DMA channels 2 and 3 to ATA, ATA enabled +#endif +#ifdef CONFIG_JULIETTE + or.d 0x3c000,r0 ; DMA channels 4 and 5 to EXTDMA0, for Juliette +#ifndef CONFIG_BLK_DEV_ETRAXIDE + or.d 0x41,r0 ; HACK for now! To make G27 connected for the RTC +#endif +#endif + move.d r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG + +#ifndef CONFIG_SVINTO_SIM + move.d r0,[R_GEN_CONFIG] + +#if 0 + moveq 4,r0 + move.b r0,[R_DMA_CH6_CMD] ; reset (ser0 dma out) + move.b r0,[R_DMA_CH7_CMD] ; reset (ser0 dma in) +w61: move.b [R_DMA_CH6_CMD],r0 ; wait for reset cycle to finish + and.b 7,r0 + cmp.b 4,r0 + beq w61 + nop +w71: move.b [R_DMA_CH7_CMD],r0 ; wait for reset cycle to finish + and.b 7,r0 + cmp.b 4,r0 + beq w71 + nop +#endif + + moveq 4,r0 + move.b r0,[R_DMA_CH8_CMD] ; reset (ser1 dma out) + move.b r0,[R_DMA_CH9_CMD] ; reset (ser1 dma in) +w81: move.b [R_DMA_CH8_CMD],r0 ; wait for reset cycle to finish + and.b 7,r0 + cmp.b 4,r0 + beq w81 + nop +w91: move.b [R_DMA_CH9_CMD],r0 ; wait for reset cycle to finish + and.b 7,r0 + cmp.b 4,r0 + beq w91 + nop + + ;; setup port PA and PB default initial directions and data + ;; including their shadow registers + + move.b DEF_R_PORT_PA_DIR,r0 + move.b r0,[_port_pa_dir_shadow] + move.b r0,[R_PORT_PA_DIR] + move.b DEF_R_PORT_PA_DATA,r0 + move.b r0,[_port_pa_data_shadow] + move.b r0,[R_PORT_PA_DATA] + + move.b DEF_R_PORT_PB_CONFIG,r0 + move.b r0,[_port_pb_config_shadow] + move.b r0,[R_PORT_PB_CONFIG] + move.b DEF_R_PORT_PB_DIR,r0 + move.b r0,[_port_pb_dir_shadow] + move.b r0,[R_PORT_PB_DIR] + move.b DEF_R_PORT_PB_DATA,r0 + move.b r0,[_port_pb_data_shadow] + move.b r0,[R_PORT_PB_DATA] + + moveq 0,r0 + move.d r0,[_port_g_data_shadow] + move.d r0,[R_PORT_G_DATA] + + ;; setup the serial port 0 at 115200 baud for debug purposes + + moveq 0,r0 + move.d r0,[R_SERIAL0_XOFF] + + move.b 0x99,r0 + move.b r0,[R_SERIAL0_BAUD] ; 115.2kbaud for both transmit and receive + + move.b 0x40,r0 ; rec enable + move.b r0,[R_SERIAL0_REC_CTRL] + + move.b 0x40,r0 ; tr enable + move.b r0,[R_SERIAL0_TR_CTRL] + + ;; setup the serial port 1 at 115200 baud for debug purposes + + moveq 0,r0 + move.d r0,[R_SERIAL1_XOFF] + + move.b 0x99,r0 + move.b r0,[R_SERIAL1_BAUD] ; 115.2kbaud for both transmit and receive + + move.b 0x40,r0 ; rec enable + move.b r0,[R_SERIAL1_REC_CTRL] + + move.b 0x40,r0 ; tr enable + move.b r0,[R_SERIAL1_TR_CTRL] + +#ifdef CONFIG_ETRAX_90000000_LEDS + ;; clear LED's on Stallone and Olga boards + moveq -1,r0 + move.d r0,[_port_90000000_shadow] + move.d r0,[0x90000000] +#endif + +#ifdef CONFIG_ETRAX100_SERIAL_PORT3 + ;; setup the serial port 3 at 115200 baud for debug purposes + + moveq 0,r0 + move.d r0,[R_SERIAL3_XOFF] + + move.b 0x99,r0 + move.b r0,[R_SERIAL3_BAUD] ; 115.2kbaud for both transmit and receive + + move.b 0x40,r0 ; rec enable + move.b r0,[R_SERIAL3_REC_CTRL] + + move.b 0x40,r0 ; tr enable + move.b r0,[R_SERIAL3_TR_CTRL] +#endif + +#endif /* CONFIG_SVINTO_SIM */ + + jump _start_kernel ; jump into the C-function _start_kernel in init/main.c + + + .data +_etrax_irv: + .dword 0 +_romfs_start: + .dword 0 +_romfs_length: + .dword 0 +_romfs_in_flash: + .dword 0 + + ;; put some special pages at the beginning of the kernel aligned + ;; to page boundaries - the kernel cannot start until after this + +#ifdef CONFIG_CRIS_LOW_MAP +_swapper_pg_dir = 0x60002000 +#else +_swapper_pg_dir = 0xc0002000 +#endif diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/hexify.c linux/arch/cris/kernel/hexify.c --- v2.4.1/linux/arch/cris/kernel/hexify.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/hexify.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,31 @@ +#include + + +void main() +{ + int c; + int comma=0; + int count=0; + while((c=getchar())!=EOF) + { + unsigned char x=c; + if(comma) + printf(","); + else + comma=1; + if(count==8) + { + count=0; + printf("\n"); + } + if(count==0) + printf("\t"); + printf("0x%02X",c); + count++; + } + if(count) + printf("\n"); + exit(0); +} + + diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c --- v2.4.1/linux/arch/cris/kernel/irq.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/irq.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,467 @@ +/* $Id: irq.c,v 1.5 2000/08/17 15:35:15 bjornw Exp $ + * + * linux/arch/cris/kernel/irq.c + * + * Copyright (c) 2000 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * This file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + * + * Notice Linux/CRIS: these routines do not care about SMP + * + */ + +/* + * IRQ's are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +char *hw_bp_msg = "BP 0x%x\n"; + +static inline void +mask_irq(unsigned int irq_nr) +{ + *R_VECT_MASK_CLR = 1 << irq_nr; +} + +static inline void +unmask_irq(unsigned int irq_nr) +{ + *R_VECT_MASK_SET = 1 << irq_nr; +} + +void +disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + save_flags(flags); + cli(); + mask_irq(irq_nr); + restore_flags(flags); +} + +void +enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + save_flags(flags); + cli(); + unmask_irq(irq_nr); + restore_flags(flags); +} + +unsigned long +probe_irq_on() +{ + return 0; +} + +int +probe_irq_off(unsigned long x) +{ + return 0; +} + +irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */ + +/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is + * global just so that the kernel gdb can use it. + */ + +void +set_int_vector(int n, irqvectptr addr, irqvectptr saddr) +{ + /* remember the shortcut entry point, after the prologue */ + + irq_shortcuts[n] = saddr; + + etrax_irv->v[n + 0x20] = (irqvectptr)addr; +} + +/* the breakpoint vector is obviously not made just like the normal irq handlers + * but needs to contain _code_ to jump to addr. + * + * the BREAK n instruction jumps to IBR + n * 8 + */ + +void +set_break_vector(int n, irqvectptr addr) +{ + unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2]; + unsigned long *jaddr = (unsigned long *)(jinstr + 1); + + /* if you don't know what this does, do not touch it! */ + + *jinstr = 0x0d3f; + *jaddr = (unsigned long)addr; + + /* 00000026 3f0d82000000 jump 0x82 */ +} + + +/* + * This builds up the IRQ handler stubs using some ugly macros in irq.h + * + * These macros create the low-level assembly IRQ routines that do all + * the operations that are needed. They are also written to be fast - and to + * disable interrupts as little as humanly possible. + * + */ + +/* IRQ0 and 1 are special traps */ +void hwbreakpoint(void); +void IRQ1_interrupt(void); +BUILD_IRQ(2, 0x04) /* the timer interrupt */ +BUILD_IRQ(3, 0x08) +BUILD_IRQ(4, 0x10) +BUILD_IRQ(5, 0x20) +BUILD_IRQ(6, 0x40) +BUILD_IRQ(7, 0x80) +BUILD_IRQ(8, 0x100) +BUILD_IRQ(9, 0x200) +BUILD_IRQ(10, 0x400) +BUILD_IRQ(11, 0x800) +BUILD_IRQ(12, 0x1000) +BUILD_IRQ(13, 0x2000) +void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */ +void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */ +BUILD_IRQ(16, 0x10000) +BUILD_IRQ(17, 0x20000) +BUILD_IRQ(18, 0x40000) +BUILD_IRQ(19, 0x80000) +BUILD_IRQ(20, 0x100000) +BUILD_IRQ(21, 0x200000) +BUILD_IRQ(22, 0x400000) +BUILD_IRQ(23, 0x800000) +BUILD_IRQ(24, 0x1000000) +BUILD_IRQ(25, 0x2000000) + +/* + * Pointers to the low-level handlers + */ + +static void (*interrupt[NR_IRQS])(void) = { + NULL, NULL, IRQ2_interrupt, IRQ3_interrupt, + IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, + IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt, + IRQ12_interrupt, IRQ13_interrupt, NULL, NULL, + IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, + IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt, + IRQ24_interrupt, IRQ25_interrupt +}; + +static void (*sinterrupt[NR_IRQS])(void) = { + NULL, NULL, sIRQ2_interrupt, sIRQ3_interrupt, + sIRQ4_interrupt, sIRQ5_interrupt, sIRQ6_interrupt, sIRQ7_interrupt, + sIRQ8_interrupt, sIRQ9_interrupt, sIRQ10_interrupt, sIRQ11_interrupt, + sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL, + sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt, + sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt, + sIRQ24_interrupt, sIRQ25_interrupt +}; + +static void (*bad_interrupt[NR_IRQS])(void) = { + NULL, NULL, + NULL, bad_IRQ3_interrupt, + bad_IRQ4_interrupt, bad_IRQ5_interrupt, + bad_IRQ6_interrupt, bad_IRQ7_interrupt, + bad_IRQ8_interrupt, bad_IRQ9_interrupt, + bad_IRQ10_interrupt, bad_IRQ11_interrupt, + bad_IRQ12_interrupt, bad_IRQ13_interrupt, + NULL, NULL, + bad_IRQ16_interrupt, bad_IRQ17_interrupt, + bad_IRQ18_interrupt, bad_IRQ19_interrupt, + bad_IRQ20_interrupt, bad_IRQ21_interrupt, + bad_IRQ22_interrupt, bad_IRQ23_interrupt, + bad_IRQ24_interrupt, bad_IRQ25_interrupt +}; + +/* + * Initial irq handlers. + */ + +static struct irqaction *irq_action[NR_IRQS] = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL +}; + +int get_irq_list(char *buf) +{ + int i, len = 0; + struct irqaction * action; + + for (i = 0; i < NR_IRQS; i++) { + action = irq_action[i]; + if (!action) + continue; + len += sprintf(buf+len, "%2d: %10u %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; +} + +/* called by the assembler IRQ entry functions defined in irq.h + * to dispatch the interrupts to registred handlers + * interrupts are disabled upon entry - depending on if the + * interrupt was registred with SA_INTERRUPT or not, interrupts + * are re-enabled or not. + */ + +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); + + if (softirq_active(cpu) & softirq_mask(cpu)) + do_softirq(); + + /* unmasking and bottom half handling is done magically for us. */ +} + +/* this function links in a handler into the chain of handlers for the + given irq, and if the irq has never been registred, the appropriate + handler is entered into the interrupt vector +*/ + +int setup_etrax_irq(int irq, struct irqaction * new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + p = irq_action + irq; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) + return -EBUSY; + + /* Can't share interrupts unless both are same type */ + if ((old->flags ^ new->flags) & SA_INTERRUPT) + return -EBUSY; + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + save_flags(flags); + cli(); + *p = new; + + if (!shared) { + /* if the irq wasn't registred before, enter it into the vector table + and unmask it physically + */ + set_int_vector(irq, interrupt[irq], sinterrupt[irq]); + unmask_irq(irq); + } + + restore_flags(flags); + return 0; +} + +/* this function is called by a driver to register an irq handler + Valid flags: + SA_INTERRUPT -> it's a fast interrupt, handler called with irq disabled and + no signal checking etc is performed upon exit + SA_SHIRQ -> the interrupt can be shared between different handlers, the handler + is required to check if the irq was "aimed" at it explicitely + SA_RANDOM -> the interrupt will add to the random generators entropy +*/ + +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + + /* interrupts 0 and 1 are hardware breakpoint and NMI and we can't support + these yet. interrupt 15 is the multiple irq, it's special. */ + + if(irq < 2 || irq == 15 || irq >= NR_IRQS) + return -EINVAL; + + if(!handler) + return -EINVAL; + + /* allocate and fill in a handler structure and setup the irq */ + + 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_etrax_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 >= NR_IRQS) { + printk("Trying to free IRQ%d\n",irq); + return; + } + for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + save_flags(flags); + cli(); + *p = action->next; + if (!irq[irq_action]) { + mask_irq(irq); + set_int_vector(irq, bad_interrupt[irq], 0); + } + restore_flags(flags); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); +} + +void weird_irq(void) +{ + __asm__("di"); + printk("weird irq\n"); + while(1); +} + +/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and + setting the irq vector table to point to bad_interrupt ptrs. +*/ + +void system_call(void); /* from entry.S */ + +void init_IRQ(void) +{ + int i; + + /* clear all interrupt masks */ + +#ifndef CONFIG_SVINTO_SIM + *R_IRQ_MASK0_CLR = 0xffffffff; + *R_IRQ_MASK1_CLR = 0xffffffff; + *R_IRQ_MASK2_CLR = 0xffffffff; +#endif + + *R_VECT_MASK_CLR = 0xffffffff; + + /* clear the shortcut entry points */ + + for(i = 0; i < NR_IRQS; i++) + irq_shortcuts[i] = NULL; + + for (i = 0; i < 256; i++) + etrax_irv->v[i] = weird_irq; + + /* set all etrax irq's to the bad handlers */ + for (i = 2; i < NR_IRQS; i++) + set_int_vector(i, bad_interrupt[i], 0); + + /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ + + set_int_vector(15, multiple_interrupt, 0); + + /* 0 and 1 which are special breakpoint/NMI traps */ + + set_int_vector(0, hwbreakpoint, 0); + set_int_vector(1, IRQ1_interrupt, 0); + + /* and irq 14 which is the mmu bus fault handler */ + + set_int_vector(14, mmu_bus_fault, 0); + + /* setup the system-call trap, which is reached by BREAK 13 */ + + set_break_vector(13, system_call); + +#ifdef CONFIG_KGDB + /* setup kgdb if its enabled, and break into the debugger */ + + kgdb_init(); + + breakpoint(); +#endif + +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/kgdb.c linux/arch/cris/kernel/kgdb.c --- v2.4.1/linux/arch/cris/kernel/kgdb.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/kgdb.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,1540 @@ +/*!************************************************************************** +*! +*! FILE NAME : kgdb.c +*! +*! DESCRIPTION: Implementation of the gdb stub with respect to ETRAX 100. +*! It is a mix of arch/m68k/kernel/kgdb.c and cris_stub.c. +*! +*!--------------------------------------------------------------------------- +*! HISTORY +*! +*! DATE NAME CHANGES +*! ---- ---- ------- +*! Apr 26 1999 Hendrik Ruijter Initial version. +*! May 6 1999 Hendrik Ruijter Removed call to strlen in libc and removed +*! struct assignment as it generates calls to +*! memcpy in libc. +*! Jun 17 1999 Hendrik Ruijter Added gdb 4.18 support. 'X', 'qC' and 'qL'. +*! Jul 21 1999 Bjorn Wesen eLinux port +*! +*! $Log: kgdb.c,v $ +*! Revision 1.2 2001/01/12 14:22:25 orjanf +*! Updated kernel debugging support to work with ETRAX 100LX. +*! +*! Revision 1.1 2000/07/10 16:25:21 bjornw +*! Initial revision +*! +*! Revision 1.1.1.1 1999/12/03 14:57:31 bjornw +*! * Initial version of arch/cris, the latest CRIS architecture with an MMU. +*! Mostly copied from arch/etrax100 with appropriate renames of files. +*! The mm/ subdir is copied from arch/i386. +*! This does not compile yet at all. +*! +*! +*! Revision 1.4 1999/07/22 17:25:25 bjornw +*! Dont wait for + in putpacket if we havent hit the initial breakpoint yet. Added a kgdb_init function which sets up the break and irq vectors. +*! +*! Revision 1.3 1999/07/21 19:51:18 bjornw +*! Check if the interrupting char is a ctrl-C, ignore otherwise. +*! +*! Revision 1.2 1999/07/21 18:09:39 bjornw +*! Ported to eLinux architecture, and added some kgdb documentation. +*! +*! +*!--------------------------------------------------------------------------- +*! +*! $Id: kgdb.c,v 1.2 2001/01/12 14:22:25 orjanf Exp $ +*! +*! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN +*! +*!**************************************************************************/ +/* @(#) cris_stub.c 1.3 06/17/99 */ + +/* + * kgdb usage notes: + * ----------------- + * + * If you select CONFIG_KGDB in the configuration, the kernel will be built + * with different gcc flags: "-g" is added to get debug infos, and + * "-fomit-frame-pointer" is omitted to make debugging easier. Since the + * resulting kernel will be quite big (approx. > 7 MB), it will be stripped + * before compresion. Such a kernel will behave just as usually, except if + * given a "debug=" command line option. (Only serial devices are + * allowed for , i.e. no printers or the like; possible values are + * machine depedend and are the same as for the usual debug device, the one + * for logging kernel messages.) If that option is given and the device can be + * initialized, the kernel will connect to the remote gdb in trap_init(). The + * serial parameters are fixed to 8N1 and 115200 bps, for easyness of + * implementation. + * + * To start a debugging session, start that gdb with the debugging kernel + * image (the one with the symbols, vmlinux.debug) named on the command line. + * This file will be used by gdb to get symbol and debugging infos about the + * kernel. Next, select remote debug mode by + * target remote + * where is the name of the serial device over which the debugged + * machine is connected. Maybe you have to adjust the baud rate by + * set remotebaud + * or also other parameters with stty: + * shell stty ... #. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + */ + + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +static int kgdb_started = 0; + +/********************************* Register image ****************************/ +/* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's + Reference", p. 1-1, with the additional register definitions of the + ETRAX 100LX in cris-opc.h. + There are 16 general 32-bit registers, R0-R15, where R14 is the stack + pointer, SP, and R15 is the program counter, PC. + There are 16 special registers, P0-P15, where three of the unimplemented + registers, P0, P4 and P8, are reserved as zero-registers. A read from + any of these registers returns zero and a write has no effect. */ + +typedef +struct register_image +{ + /* Offset */ + unsigned int r0; /* 0x00 */ + unsigned int r1; /* 0x04 */ + unsigned int r2; /* 0x08 */ + unsigned int r3; /* 0x0C */ + unsigned int r4; /* 0x10 */ + unsigned int r5; /* 0x14 */ + unsigned int r6; /* 0x18 */ + unsigned int r7; /* 0x1C */ + unsigned int r8; /* 0x20 Frame pointer */ + unsigned int r9; /* 0x24 */ + unsigned int r10; /* 0x28 */ + unsigned int r11; /* 0x2C */ + unsigned int r12; /* 0x30 */ + unsigned int r13; /* 0x34 */ + unsigned int sp; /* 0x38 Stack pointer */ + unsigned int pc; /* 0x3C Program counter */ + + unsigned char p0; /* 0x40 8-bit zero-register */ + unsigned char vr; /* 0x41 Version register */ + + unsigned short p4; /* 0x42 16-bit zero-register */ + unsigned short ccr; /* 0x44 Condition code register */ + + unsigned int mof; /* 0x46 Multiply overflow register */ + + unsigned int p8; /* 0x4A 32-bit zero-register */ + unsigned int ibr; /* 0x4E Interrupt base register */ + unsigned int irp; /* 0x52 Interrupt return pointer */ + unsigned int srp; /* 0x56 Subroutine return pointer */ + unsigned int bar; /* 0x5A Breakpoint address register */ + unsigned int dccr; /* 0x5E Double condition code register */ + unsigned int brp; /* 0x62 Breakpoint return pointer (pc in caller) */ + unsigned int usp; /* 0x66 User mode stack pointer */ +} registers; + +/************** Prototypes for local library functions ***********************/ + +/* Copy of strcpy from libc. */ +static char *gdb_cris_strcpy (char *s1, const char *s2); + +/* Copy of strlen from libc. */ +static int gdb_cris_strlen (const char *s); + +/* Copy of memchr from libc. */ +static void *gdb_cris_memchr (const void *s, int c, int n); + +/* Copy of strtol from libc. Does only support base 16. */ +static int gdb_cris_strtol (const char *s, char **endptr, int base); + +/********************** Prototypes for local functions. **********************/ +/* Copy the content of a register image into another. The size n is + the size of the register image. Due to struct assignment generation of + memcpy in libc. */ +static void copy_registers (registers *dptr, registers *sptr, int n); + +/* Copy the stored registers from the stack. Put the register contents + of thread thread_id in the struct reg. */ +static void copy_registers_from_stack (int thread_id, registers *reg); + +/* Copy the registers to the stack. Put the register contents of thread + thread_id from struct reg to the stack. */ +static void copy_registers_to_stack (int thread_id, registers *reg); + +/* Write a value to a specified register regno in the register image + of the current thread. */ +static int write_register (int regno, char *val); + +/* Write a value to a specified register in the stack of a thread other + than the current thread. */ +static write_stack_register (int thread_id, int regno, char *valptr); + +/* Read a value from a specified register in the register image. Returns the + status of the read operation. The register value is returned in valptr. */ +static int read_register (char regno, unsigned int *valptr); + +/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */ +int getDebugChar (void); + +/* Serial port, writes one character. ETRAX 100 specific. from debugport.c */ +void putDebugChar (int val); + +void enableDebugIRQ (void); + +/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte, + represented by int x. */ +static char highhex (int x); + +/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte, + represented by int x. */ +static char lowhex (int x); + +/* Returns the integer equivalent of a hexadecimal character. */ +static int hex (char ch); + +/* Convert the memory, pointed to by mem into hexadecimal representation. + Put the result in buf, and return a pointer to the last character + in buf (null). */ +static char *mem2hex (char *buf, unsigned char *mem, int count); + +/* Convert the array, in hexadecimal representation, pointed to by buf into + binary representation. Put the result in mem, and return a pointer to + the character after the last byte written. */ +static unsigned char *hex2mem (unsigned char *mem, char *buf, int count); + +/* Put the content of the array, in binary representation, pointed to by buf + into memory pointed to by mem, and return a pointer to + the character after the last byte written. */ +static unsigned char *bin2mem (unsigned char *mem, unsigned char *buf, int count); + +/* Await the sequence $# and store in the array buffer + returned. */ +static void getpacket (char *buffer); + +/* Send $# from the in the array buffer. */ +static void putpacket (char *buffer); + +/* Build and send a response packet in order to inform the host the + stub is stopped. */ +static void stub_is_stopped (int sigval); + +/* All expected commands are sent from remote.c. Send a response according + to the description in remote.c. */ +static void handle_exception (int sigval); + +/* Performs a complete re-start from scratch. ETRAX specific. */ +static void kill_restart (void); + +/******************** Prototypes for global functions. ***********************/ + +/* The string str is prepended with the GDB printout token and sent. */ +void putDebugString (const unsigned char *str, int length); /* used by etrax100ser.c */ + +/* The hook for both static (compiled) and dynamic breakpoints set by GDB. + ETRAX 100 specific. */ +void handle_breakpoint (void); /* used by irq.c */ + +/* The hook for an interrupt generated by GDB. ETRAX 100 specific. */ +void handle_interrupt (void); /* used by irq.c */ + +/* A static breakpoint to be used at startup. */ +void breakpoint (void); /* called by init/main.c */ + +/* From osys_int.c, executing_task contains the number of the current + executing task in osys. Does not know of object-oriented threads. */ +extern unsigned char executing_task; + +/* The number of characters used for a 64 bit thread identifier. */ +#define HEXCHARS_IN_THREAD_ID 16 + +/* Avoid warning as the internal_stack is not used in the C-code. */ +#define USEDVAR(name) { if (name) { ; } } +#define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) } + +/********************************** Packet I/O ******************************/ +/* BUFMAX defines the maximum number of characters in + inbound/outbound buffers */ +#define BUFMAX 512 + +/* Run-length encoding maximum length. Send 64 at most. */ +#define RUNLENMAX 64 + +/* Definition of all valid hexadecimal characters */ +static const char hexchars[] = "0123456789abcdef"; + +/* The inbound/outbound buffers used in packet I/O */ +static char remcomInBuffer[BUFMAX]; +static char remcomOutBuffer[BUFMAX]; + +/* Error and warning messages. */ +enum error_type +{ + SUCCESS, E01, E02, E03, E04, E05, E06, E07 +}; +static char *error_message[] = +{ + "", + "E01 Set current or general thread - H[c,g] - internal error.", + "E02 Change register content - P - cannot change read-only register.", + "E03 Thread is not alive.", /* T, not used. */ + "E04 The command is not supported - [s,C,S,!,R,d,r] - internal error.", + "E05 Change register content - P - the register is not implemented..", + "E06 Change memory content - M - internal error.", + "E07 Change register content - P - the register is not stored on the stack" +}; +/********************************* Register image ****************************/ +/* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's + Reference", p. 1-1, with the additional register definitions of the + ETRAX 100LX in cris-opc.h. + There are 16 general 32-bit registers, R0-R15, where R14 is the stack + pointer, SP, and R15 is the program counter, PC. + There are 16 special registers, P0-P15, where three of the unimplemented + registers, P0, P4 and P8, are reserved as zero-registers. A read from + any of these registers returns zero and a write has no effect. */ +enum register_name +{ + R0, R1, R2, R3, + R4, R5, R6, R7, + R8, R9, R10, R11, + R12, R13, SP, PC, + P0, VR, P2, P3, + P4, CCR, P6, MOF, + P8, IBR, IRP, SRP, + BAR, DCCR, BRP, USP +}; + +/* The register sizes of the registers in register_name. An unimplemented register + is designated by size 0 in this array. */ +static int register_size[] = +{ + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 4, 4, 4, 4, + 1, 1, 0, 0, + 2, 2, 0, 4, + 4, 4, 4, 4, + 4, 4, 4, 4 +}; + +/* Contains the register image of the executing thread in the assembler + part of the code in order to avoid horrible addressing modes. */ +static registers reg; + +/* FIXME: Should this be used? Delete otherwise. */ +/* Contains the assumed consistency state of the register image. Uses the + enum error_type for state information. */ +static int consistency_status = SUCCESS; + +/********************************** Handle exceptions ************************/ +/* The variable reg contains the register image associated with the + current_thread_c variable. It is a complete register image created at + entry. The reg_g contains a register image of a task where the general + registers are taken from the stack and all special registers are taken + from the executing task. It is associated with current_thread_g and used + in order to provide access mainly for 'g', 'G' and 'P'. +*/ + +/* Need two task id pointers in order to handle Hct and Hgt commands. */ +static int current_thread_c = 0; +static int current_thread_g = 0; + +/* Need two register images in order to handle Hct and Hgt commands. The + variable reg_g is in addition to reg above. */ +static registers reg_g; + +/********************************** Breakpoint *******************************/ +/* Use an internal stack in the breakpoint and interrupt response routines */ +#define INTERNAL_STACK_SIZE 1024 +static char internal_stack[INTERNAL_STACK_SIZE]; + +/* Due to the breakpoint return pointer, a state variable is needed to keep + track of whether it is a static (compiled) or dynamic (gdb-invoked) + breakpoint to be handled. A static breakpoint uses the content of register + BRP as it is whereas a dynamic breakpoint requires subtraction with 2 + in order to execute the instruction. The first breakpoint is static. */ +static unsigned char is_dyn_brkp = 0; + +/********************************* String library ****************************/ +/* Single-step over library functions creates trap loops. */ + +/* Copy char s2[] to s1[]. */ +static char* +gdb_cris_strcpy (char *s1, const char *s2) +{ + char *s = s1; + + for (s = s1; (*s++ = *s2++) != '\0'; ) + ; + return (s1); +} + +/* Find length of s[]. */ +static int +gdb_cris_strlen (const char *s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; sc++) + ; + return (sc - s); +} + +/* Find first occurrence of c in s[n]. */ +static void* +gdb_cris_memchr (const void *s, int c, int n) +{ + const unsigned char uc = c; + const unsigned char *su; + + for (su = s; 0 < n; ++su, --n) + if (*su == uc) + return ((void *)su); + return (NULL); +} +/******************************* Standard library ****************************/ +/* Single-step over library functions creates trap loops. */ +/* Convert string to long. */ +static int +gdb_cris_strtol (const char *s, char **endptr, int base) +{ + char *s1; + char *sd; + int x = 0; + + for (s1 = (char*)s; (sd = gdb_cris_memchr(hexchars, *s1, base)) != NULL; ++s1) + x = x * base + (sd - hexchars); + + if (endptr) + { + /* Unconverted suffix is stored in endptr unless endptr is NULL. */ + *endptr = s1; + } + + return x; +} + +int +double_this(int x) +{ + return 2 * x; +} + +/********************************* Register image ****************************/ +/* Copy the content of a register image into another. The size n is + the size of the register image. Due to struct assignment generation of + memcpy in libc. */ +static void +copy_registers (registers *dptr, registers *sptr, int n) +{ + unsigned char *dreg; + unsigned char *sreg; + + for (dreg = (unsigned char*)dptr, sreg = (unsigned char*)sptr; n > 0; n--) + *dreg++ = *sreg++; +} + +#ifdef PROCESS_SUPPORT +/* Copy the stored registers from the stack. Put the register contents + of thread thread_id in the struct reg. */ +static void +copy_registers_from_stack (int thread_id, registers *regptr) +{ + int j; + stack_registers *s = (stack_registers *)stack_list[thread_id]; + unsigned int *d = (unsigned int *)regptr; + + for (j = 13; j >= 0; j--) + *d++ = s->r[j]; + regptr->sp = (unsigned int)stack_list[thread_id]; + regptr->pc = s->pc; + regptr->dccr = s->dccr; + regptr->srp = s->srp; +} + +/* Copy the registers to the stack. Put the register contents of thread + thread_id from struct reg to the stack. */ +static void +copy_registers_to_stack (int thread_id, registers *regptr) +{ + int i; + stack_registers *d = (stack_registers *)stack_list[thread_id]; + unsigned int *s = (unsigned int *)regptr; + + for (i = 0; i < 14; i++) { + d->r[i] = *s++; + } + d->pc = regptr->pc; + d->dccr = regptr->dccr; + d->srp = regptr->srp; +} +#endif + +/* Write a value to a specified register in the register image of the current + thread. Returns status code SUCCESS, E02 or E05. */ +static int +write_register (int regno, char *val) +{ + int status = SUCCESS; + registers *current_reg = ® + + if (regno >= R0 && regno <= PC) { + /* 32-bit register with simple offset. */ + hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int), + val, sizeof(unsigned int)); + } + else if (regno == P0 || regno == VR || regno == P4 || regno == P8) { + /* Do not support read-only registers. */ + status = E02; + } + else if (regno == CCR) { + /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented, + and P7 (MOF) is 32 bits in ETRAX 100LX. */ + hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short), + val, sizeof(unsigned short)); + } + else if (regno >= MOF && regno <= USP) { + /* 32 bit register with complex offset. (P8 has been taken care of.) */ + hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int), + val, sizeof(unsigned int)); + } + else { + /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */ + status = E05; + } + return status; +} + +#ifdef PROCESS_SUPPORT +/* Write a value to a specified register in the stack of a thread other + than the current thread. Returns status code SUCCESS or E07. */ +static int +write_stack_register (int thread_id, int regno, char *valptr) +{ + int status = SUCCESS; + stack_registers *d = (stack_registers *)stack_list[thread_id]; + unsigned int val; + + hex2mem ((unsigned char *)&val, valptr, sizeof(unsigned int)); + if (regno >= R0 && regno < SP) { + d->r[regno] = val; + } + else if (regno == SP) { + stack_list[thread_id] = val; + } + else if (regno == PC) { + d->pc = val; + } + else if (regno == SRP) { + d->srp = val; + } + else if (regno == DCCR) { + d->dccr = val; + } + else { + /* Do not support registers in the current thread. */ + status = E07; + } + return status; +} +#endif + +/* Read a value from a specified register in the register image. Returns the + value in the register or -1 for non-implemented registers. + Should check consistency_status after a call which may be E05 after changes + in the implementation. */ +static int +read_register (char regno, unsigned int *valptr) +{ + registers *current_reg = ® + + if (regno >= R0 && regno <= PC) { + /* 32-bit register with simple offset. */ + *valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int)); + return SUCCESS; + } + else if (regno == P0 || regno == VR) { + /* 8 bit register with complex offset. */ + *valptr = (unsigned int)(*(unsigned char *) + ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char))); + return SUCCESS; + } + else if (regno == P4 || regno == CCR) { + /* 16 bit register with complex offset. */ + *valptr = (unsigned int)(*(unsigned short *) + ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short))); + return SUCCESS; + } + else if (regno >= MOF && regno <= USP) { + /* 32 bit register with complex offset. */ + *valptr = *(unsigned int *)((char *)&(current_reg->p8) + + (regno-P8) * sizeof(unsigned int)); + return SUCCESS; + } + else { + /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */ + consistency_status = E05; + return E05; + } +} + +/********************************** Packet I/O ******************************/ +/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte, + represented by int x. */ +static inline char +highhex(int x) +{ + return hexchars[(x >> 4) & 0xf]; +} + +/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte, + represented by int x. */ +static inline char +lowhex(int x) +{ + return hexchars[x & 0xf]; +} + +/* Returns the integer equivalent of a hexadecimal character. */ +static int +hex (char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* Convert the memory, pointed to by mem into hexadecimal representation. + Put the result in buf, and return a pointer to the last character + in buf (null). */ + +static int do_printk = 0; + +static char * +mem2hex(char *buf, unsigned char *mem, int count) +{ + int i; + int ch; + + if (mem == NULL) { + /* Bogus read from m0. FIXME: What constitutes a valid address? */ + for (i = 0; i < count; i++) { + *buf++ = '0'; + *buf++ = '0'; + } + } else { + /* Valid mem address. */ + for (i = 0; i < count; i++) { + ch = *mem++; + *buf++ = highhex (ch); + *buf++ = lowhex (ch); + } + } + + /* Terminate properly. */ + *buf = '\0'; + return (buf); +} + +/* Convert the array, in hexadecimal representation, pointed to by buf into + binary representation. Put the result in mem, and return a pointer to + the character after the last byte written. */ +static unsigned char* +hex2mem (unsigned char *mem, char *buf, int count) +{ + int i; + unsigned char ch; + for (i = 0; i < count; i++) { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + *mem++ = ch; + } + return (mem); +} + +/* Put the content of the array, in binary representation, pointed to by buf + into memory pointed to by mem, and return a pointer to the character after + the last byte written. + Gdb will escape $, #, and the escape char (0x7d). */ +static unsigned char* +bin2mem (unsigned char *mem, unsigned char *buf, int count) +{ + int i; + unsigned char *next; + for (i = 0; i < count; i++) { + /* Check for any escaped characters. Be paranoid and + only unescape chars that should be escaped. */ + if (*buf == 0x7d) { + next = buf + 1; + if (*next == 0x3 || *next == 0x4 || *next == 0x5D) /* #, $, ESC */ + { + buf++; + *buf += 0x20; + } + } + *mem++ = *buf++; + } + return (mem); +} + +/* Await the sequence $# and store in the array buffer + returned. */ +static void +getpacket (char *buffer) +{ + unsigned char checksum; + unsigned char xmitcsum; + int i; + int count; + char ch; + do { + while ((ch = getDebugChar ()) != '$') + /* Wait for the start character $ and ignore all other characters */; + checksum = 0; + xmitcsum = -1; + count = 0; + /* Read until a # or the end of the buffer is reached */ + while (count < BUFMAX) { + ch = getDebugChar (); + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = '\0'; + + if (ch == '#') { + xmitcsum = hex (getDebugChar ()) << 4; + xmitcsum += hex (getDebugChar ()); + if (checksum != xmitcsum) { + /* Wrong checksum */ + putDebugChar ('-'); + } + else { + /* Correct checksum */ + putDebugChar ('+'); + /* If sequence characters are received, reply with them */ + if (buffer[2] == ':') { + putDebugChar (buffer[0]); + putDebugChar (buffer[1]); + /* Remove the sequence characters from the buffer */ + count = gdb_cris_strlen (buffer); + for (i = 3; i <= count; i++) + buffer[i - 3] = buffer[i]; + } + } + } + } while (checksum != xmitcsum); +} + +/* Send $# from the in the array buffer. */ + +static void +putpacket(char *buffer) +{ + int checksum; + int runlen; + int encode; + + do { + char *src = buffer; + putDebugChar ('$'); + checksum = 0; + while (*src) { + /* Do run length encoding */ + putDebugChar (*src); + checksum += *src; + runlen = 0; + while (runlen < RUNLENMAX && *src == src[runlen]) { + runlen++; + } + if (runlen > 3) { + /* Got a useful amount */ + putDebugChar ('*'); + checksum += '*'; + encode = runlen + ' ' - 4; + putDebugChar (encode); + checksum += encode; + src += runlen; + } + else { + src++; + } + } + putDebugChar ('#'); + putDebugChar (highhex (checksum)); + putDebugChar (lowhex (checksum)); + } while(kgdb_started && (getDebugChar() != '+')); +} + +/* The string str is prepended with the GDB printout token and sent. Required + in traditional implementations. */ +void +putDebugString (const unsigned char *str, int length) +{ + remcomOutBuffer[0] = 'O'; + mem2hex(&remcomOutBuffer[1], (unsigned char *)str, length); + putpacket(remcomOutBuffer); +} + +/********************************** Handle exceptions ************************/ +/* Build and send a response packet in order to inform the host the + stub is stopped. TAAn...:r...;n...:r...;n...:r...; + AA = signal number + n... = register number (hex) + r... = register contents + n... = `thread' + r... = thread process ID. This is a hex integer. + n... = other string not starting with valid hex digit. + gdb should ignore this n,r pair and go on to the next. + This way we can extend the protocol. */ +static void +stub_is_stopped(int sigval) +{ + char *ptr = remcomOutBuffer; + int regno; + + unsigned int reg_cont; + int status; + + /* Send trap type (converted to signal) */ + + *ptr++ = 'T'; + *ptr++ = highhex (sigval); + *ptr++ = lowhex (sigval); + + /* Send register contents. We probably only need to send the + * PC, frame pointer and stack pointer here. Other registers will be + * explicitely asked for. But for now, send all. + */ + + for (regno = R0; regno <= USP; regno++) { + /* Store n...:r...; for the registers in the buffer. */ + + status = read_register (regno, ®_cont); + + if (status == SUCCESS) { + + *ptr++ = highhex (regno); + *ptr++ = lowhex (regno); + *ptr++ = ':'; + + ptr = mem2hex(ptr, (unsigned char *)®_cont, + register_size[regno]); + *ptr++ = ';'; + } + + } + +#ifdef PROCESS_SUPPORT + /* Store the registers of the executing thread. Assume that both step, + continue, and register content requests are with respect to this + thread. The executing task is from the operating system scheduler. */ + + current_thread_c = executing_task; + current_thread_g = executing_task; + + /* A struct assignment translates into a libc memcpy call. Avoid + all libc functions in order to prevent recursive break points. */ + copy_registers (®_g, ®, sizeof(registers)); + + /* Store thread:r...; with the executing task TID. */ + gdb_cris_strcpy (&remcomOutBuffer[pos], "thread:"); + pos += gdb_cris_strlen ("thread:"); + remcomOutBuffer[pos++] = highhex (executing_task); + remcomOutBuffer[pos++] = lowhex (executing_task); + gdb_cris_strcpy (&remcomOutBuffer[pos], ";"); +#endif + + /* null-terminate and send it off */ + + *ptr = 0; + + putpacket (remcomOutBuffer); +} + +/* All expected commands are sent from remote.c. Send a response according + to the description in remote.c. */ +static void +handle_exception (int sigval) +{ + /* Avoid warning of not used. */ + + USEDFUN(handle_exception); + USEDVAR(internal_stack[0]); + + /* Send response. */ + + stub_is_stopped (sigval); + + for (;;) { + remcomOutBuffer[0] = '\0'; + getpacket (remcomInBuffer); + switch (remcomInBuffer[0]) { + case 'g': + /* Read registers: g + Success: Each byte of register data is described by two hex digits. + Registers are in the internal order for GDB, and the bytes + in a register are in the same order the machine uses. + Failure: void. */ + + { +#ifdef PROCESS_SUPPORT + /* Use the special register content in the executing thread. */ + copy_registers (®_g, ®, sizeof(registers)); + /* Replace the content available on the stack. */ + if (current_thread_g != executing_task) { + copy_registers_from_stack (current_thread_g, ®_g); + } + mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)®_g, sizeof(registers)); +#else + mem2hex(remcomOutBuffer, (char *)®, sizeof(registers)); +#endif + } + break; + + case 'G': + /* Write registers. GXX..XX + Each byte of register data is described by two hex digits. + Success: OK + Failure: void. */ +#ifdef PROCESS_SUPPORT + hex2mem ((unsigned char *)®_g, &remcomInBuffer[1], sizeof(registers)); + if (current_thread_g == executing_task) { + copy_registers (®, ®_g, sizeof(registers)); + } + else { + copy_registers_to_stack(current_thread_g, ®_g); + } +#else + hex2mem((char *)®, &remcomInBuffer[1], sizeof(registers)); +#endif + gdb_cris_strcpy (remcomOutBuffer, "OK"); + break; + + case 'P': + /* Write register. Pn...=r... + Write register n..., hex value without 0x, with value r..., + which contains a hex value without 0x and two hex digits + for each byte in the register (target byte order). P1f=11223344 means + set register 31 to 44332211. + Success: OK + Failure: E02, E05 */ + { + char *suffix; + int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16); + int status; +#ifdef PROCESS_SUPPORT + if (current_thread_g =! executing_task) + status = write_stack_register (current_thread_g, regno, suffix+1); + else +#endif + status = write_register (regno, suffix+1); + + switch (status) { + case E02: + /* Do not support read-only registers. */ + gdb_cris_strcpy (remcomOutBuffer, error_message[E02]); + break; + case E05: + /* Do not support non-existing registers. */ + gdb_cris_strcpy (remcomOutBuffer, error_message[E05]); + break; + case E07: + /* Do not support non-existing registers on the stack. */ + gdb_cris_strcpy (remcomOutBuffer, error_message[E07]); + break; + default: + /* Valid register number. */ + gdb_cris_strcpy (remcomOutBuffer, "OK"); + break; + } + } + break; + + case 'm': + /* Read from memory. mAA..AA,LLLL + AA..AA is the address and LLLL is the length. + Success: XX..XX is the memory content. Can be fewer bytes than + requested if only part of the data may be read. m6000120a,6c means + retrieve 108 byte from base address 6000120a. + Failure: void. */ + { + char *suffix; + unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1], + &suffix, 16); int length = gdb_cris_strtol(suffix+1, 0, 16); + + mem2hex(remcomOutBuffer, addr, length); + } + break; + + case 'X': + /* Write to memory. XAA..AA,LLLL:XX..XX + AA..AA is the start address, LLLL is the number of bytes, and + XX..XX is the binary data. + Success: OK + Failure: void. */ + case 'M': + /* Write to memory. MAA..AA,LLLL:XX..XX + AA..AA is the start address, LLLL is the number of bytes, and + XX..XX is the hexadecimal data. + Success: OK + Failure: void. */ + { + char *lenptr; + char *dataptr; + unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1], + &lenptr, 16); + int length = gdb_cris_strtol(lenptr+1, &dataptr, 16); + if (*lenptr == ',' && *dataptr == ':') { + if (remcomInBuffer[0] == 'M') { + hex2mem(addr, dataptr + 1, length); + } + else /* X */ { + bin2mem(addr, dataptr + 1, length); + } + gdb_cris_strcpy (remcomOutBuffer, "OK"); + } + else { + gdb_cris_strcpy (remcomOutBuffer, error_message[E06]); + } + } + break; + + case 'c': + /* Continue execution. cAA..AA + AA..AA is the address where execution is resumed. If AA..AA is + omitted, resume at the present address. + Success: return to the executing thread. + Failure: will never know. */ + if (remcomInBuffer[1] != '\0') { + reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16); + } + enableDebugIRQ(); + return; + + case 's': + /* Step. sAA..AA + AA..AA is the address where execution is resumed. If AA..AA is + omitted, resume at the present address. Success: return to the + executing thread. Failure: will never know. + + Should never be invoked. The single-step is implemented on + the host side. If ever invoked, it is an internal error E04. */ + gdb_cris_strcpy (remcomOutBuffer, error_message[E04]); + putpacket (remcomOutBuffer); + return; + + case '?': + /* The last signal which caused a stop. ? + Success: SAA, where AA is the signal number. + Failure: void. */ + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = highhex (sigval); + remcomOutBuffer[2] = lowhex (sigval); + remcomOutBuffer[3] = 0; + break; + + case 'D': + /* Detach from host. D + Success: OK, and return to the executing thread. + Failure: will never know */ + putpacket ("OK"); + return; + + case 'k': + case 'r': + /* kill request or reset request. + Success: restart of target. + Failure: will never know. */ + kill_restart (); + break; + + case 'C': + case 'S': + case '!': + case 'R': + case 'd': + /* Continue with signal sig. Csig;AA..AA + Step with signal sig. Ssig;AA..AA + Use the extended remote protocol. ! + Restart the target system. R0 + Toggle debug flag. d + Search backwards. tAA:PP,MM + Not supported: E04 */ + gdb_cris_strcpy (remcomOutBuffer, error_message[E04]); + break; +#ifdef PROCESS_SUPPORT + + case 'T': + /* Thread alive. TXX + Is thread XX alive? + Success: OK, thread XX is alive. + Failure: E03, thread XX is dead. */ + { + int thread_id = (int)gdb_cris_strtol (&remcomInBuffer[1], 0, 16); + /* Cannot tell whether it is alive or not. */ + if (thread_id >= 0 && thread_id < number_of_tasks) + gdb_cris_strcpy (remcomOutBuffer, "OK"); + } + break; + + case 'H': + /* Set thread for subsequent operations: Hct + c = 'c' for thread used in step and continue; + t can be -1 for all threads. + c = 'g' for thread used in other operations. + t = 0 means pick any thread. + Success: OK + Failure: E01 */ + { + int thread_id = gdb_cris_strtol (&remcomInBuffer[2], 0, 16); + if (remcomInBuffer[1] == 'c') { + /* c = 'c' for thread used in step and continue */ + /* Do not change current_thread_c here. It would create a mess in + the scheduler. */ + gdb_cris_strcpy (remcomOutBuffer, "OK"); + } + else if (remcomInBuffer[1] == 'g') { + /* c = 'g' for thread used in other operations. + t = 0 means pick any thread. Impossible since the scheduler does + not allow that. */ + if (thread_id >= 0 && thread_id < number_of_tasks) { + current_thread_g = thread_id; + gdb_cris_strcpy (remcomOutBuffer, "OK"); + } + else { + /* Not expected - send an error message. */ + gdb_cris_strcpy (remcomOutBuffer, error_message[E01]); + } + } + else { + /* Not expected - send an error message. */ + gdb_cris_strcpy (remcomOutBuffer, error_message[E01]); + } + } + break; + + case 'q': + case 'Q': + /* Query of general interest. qXXXX + Set general value XXXX. QXXXX=yyyy */ + { + int pos; + int nextpos; + int thread_id; + + switch (remcomInBuffer[1]) { + case 'C': + /* Identify the remote current thread. */ + gdb_cris_strcpy (&remcomOutBuffer[0], "QC"); + remcomOutBuffer[2] = highhex (current_thread_c); + remcomOutBuffer[3] = lowhex (current_thread_c); + remcomOutBuffer[4] = '\0'; + break; + case 'L': + gdb_cris_strcpy (&remcomOutBuffer[0], "QM"); + /* Reply with number of threads. */ + if (os_is_started()) { + remcomOutBuffer[2] = highhex (number_of_tasks); + remcomOutBuffer[3] = lowhex (number_of_tasks); + } + else { + remcomOutBuffer[2] = highhex (0); + remcomOutBuffer[3] = lowhex (1); + } + /* Done with the reply. */ + remcomOutBuffer[4] = lowhex (1); + pos = 5; + /* Expects the argument thread id. */ + for (; pos < (5 + HEXCHARS_IN_THREAD_ID); pos++) + remcomOutBuffer[pos] = remcomInBuffer[pos]; + /* Reply with the thread identifiers. */ + if (os_is_started()) { + /* Store the thread identifiers of all tasks. */ + for (thread_id = 0; thread_id < number_of_tasks; thread_id++) { + nextpos = pos + HEXCHARS_IN_THREAD_ID - 1; + for (; pos < nextpos; pos ++) + remcomOutBuffer[pos] = lowhex (0); + remcomOutBuffer[pos++] = lowhex (thread_id); + } + } + else { + /* Store the thread identifier of the boot task. */ + nextpos = pos + HEXCHARS_IN_THREAD_ID - 1; + for (; pos < nextpos; pos ++) + remcomOutBuffer[pos] = lowhex (0); + remcomOutBuffer[pos++] = lowhex (current_thread_c); + } + remcomOutBuffer[pos] = '\0'; + break; + default: + /* Not supported: "" */ + /* Request information about section offsets: qOffsets. */ + remcomOutBuffer[0] = 0; + break; + } + } + break; +#endif /* PROCESS_SUPPORT */ + + default: + /* The stub should ignore other request and send an empty + response ($#). This way we can extend the protocol and GDB + can tell whether the stub it is talking to uses the old or the new. */ + remcomOutBuffer[0] = 0; + break; + } + putpacket(remcomOutBuffer); + } +} + +/* The jump is to the address 0x00000002. Performs a complete re-start + from scratch. */ +static void +kill_restart () +{ + __asm__ volatile ("jump 2"); +} + +/********************************** Breakpoint *******************************/ +/* The hook for both a static (compiled) and a dynamic breakpoint set by GDB. + An internal stack is used by the stub. The register image of the caller is + stored in the structure register_image. + Interactive communication with the host is handled by handle_exception and + finally the register image is restored. */ + +void kgdb_handle_breakpoint(void); + +asm (" + .global _kgdb_handle_breakpoint +_kgdb_handle_breakpoint: +;; +;; Response to the break-instruction +;; +;; Create a register image of the caller +;; + move dccr,[_reg+0x5E] ; Save the flags in DCCR before disable interrupts + di ; Disable interrupts + move.d r0,[_reg] ; Save R0 + move.d r1,[_reg+0x04] ; Save R1 + move.d r2,[_reg+0x08] ; Save R2 + move.d r3,[_reg+0x0C] ; Save R3 + move.d r4,[_reg+0x10] ; Save R4 + move.d r5,[_reg+0x14] ; Save R5 + move.d r6,[_reg+0x18] ; Save R6 + move.d r7,[_reg+0x1C] ; Save R7 + move.d r8,[_reg+0x20] ; Save R8 + move.d r9,[_reg+0x24] ; Save R9 + move.d r10,[_reg+0x28] ; Save R10 + move.d r11,[_reg+0x2C] ; Save R11 + move.d r12,[_reg+0x30] ; Save R12 + move.d r13,[_reg+0x34] ; Save R13 + move.d sp,[_reg+0x38] ; Save SP (R14) +;; Due to the old assembler-versions BRP might not be recognized + .word 0xE670 ; move brp,r0 + subq 2,r0 ; Set to address of previous instruction. + move.d r0,[_reg+0x3c] ; Save the address in PC (R15) + clear.b [_reg+0x40] ; Clear P0 + move vr,[_reg+0x41] ; Save special register P1 + clear.w [_reg+0x42] ; Clear P4 + move ccr,[_reg+0x44] ; Save special register CCR + move mof,[_reg+0x46] ; P7 + clear.d [_reg+0x4A] ; Clear P8 + move ibr,[_reg+0x4E] ; P9, + move irp,[_reg+0x52] ; P10, + move srp,[_reg+0x56] ; P11, + move dtp0,[_reg+0x5A] ; P12, register BAR, assembler might not know BAR + ; P13, register DCCR already saved +;; Due to the old assembler-versions BRP might not be recognized + .word 0xE670 ; move brp,r0 +;; Static (compiled) breakpoints must return to the next instruction in order +;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction +;; in order to execute it when execution is continued. + test.b [_is_dyn_brkp] ; Is this a dynamic breakpoint? + beq is_static ; No, a static breakpoint + nop + subq 2,r0 ; rerun the instruction the break replaced +is_static: + moveq 1,r1 + move.b r1,[_is_dyn_brkp] ; Set the state variable to dynamic breakpoint + move.d r0,[_reg+0x62] ; Save the return address in BRP + move usp,[_reg+0x66] ; USP +;; +;; Handle the communication +;; + move.d _internal_stack+1020,sp ; Use the internal stack which grows upward + moveq 5,r10 ; SIGTRAP + jsr _handle_exception ; Interactive routine +;; +;; Return to the caller +;; + move.d [_reg],r0 ; Restore R0 + move.d [_reg+0x04],r1 ; Restore R1 + move.d [_reg+0x08],r2 ; Restore R2 + move.d [_reg+0x0C],r3 ; Restore R3 + move.d [_reg+0x10],r4 ; Restore R4 + move.d [_reg+0x14],r5 ; Restore R5 + move.d [_reg+0x18],r6 ; Restore R6 + move.d [_reg+0x1C],r7 ; Restore R7 + move.d [_reg+0x20],r8 ; Restore R8 + move.d [_reg+0x24],r9 ; Restore R9 + move.d [_reg+0x28],r10 ; Restore R10 + move.d [_reg+0x2C],r11 ; Restore R11 + move.d [_reg+0x30],r12 ; Restore R12 + move.d [_reg+0x34],r13 ; Restore R13 +;; +;; FIXME: Which registers should be restored? +;; + move.d [_reg+0x38],sp ; Restore SP (R14) + move [_reg+0x56],srp ; Restore the subroutine return pointer. + move [_reg+0x5E],dccr ; Restore DCCR + move [_reg+0x66],usp ; Restore USP + jump [_reg+0x62] ; A jump to the content in register BRP works. + nop ; +"); + +/* The hook for an interrupt generated by GDB. An internal stack is used + by the stub. The register image of the caller is stored in the structure + register_image. Interactive communication with the host is handled by + handle_exception and finally the register image is restored. Due to the + old assembler which does not recognise the break instruction and the + breakpoint return pointer hex-code is used. */ + +void kgdb_handle_serial(void); + +asm (" + .global _kgdb_handle_serial +_kgdb_handle_serial: +;; +;; Response to a serial interrupt +;; + + move dccr,[_reg+0x5E] ; Save the flags in DCCR + di ; Disable interrupts + move.d r0,[_reg] ; Save R0 + move.d r1,[_reg+0x04] ; Save R1 + move.d r2,[_reg+0x08] ; Save R2 + move.d r3,[_reg+0x0C] ; Save R3 + move.d r4,[_reg+0x10] ; Save R4 + move.d r5,[_reg+0x14] ; Save R5 + move.d r6,[_reg+0x18] ; Save R6 + move.d r7,[_reg+0x1C] ; Save R7 + move.d r8,[_reg+0x20] ; Save R8 + move.d r9,[_reg+0x24] ; Save R9 + move.d r10,[_reg+0x28] ; Save R10 + move.d r11,[_reg+0x2C] ; Save R11 + move.d r12,[_reg+0x30] ; Save R12 + move.d r13,[_reg+0x34] ; Save R13 + move.d sp,[_reg+0x38] ; Save SP (R14) + move irp,[_reg+0x3c] ; Save the address in PC (R15) + clear.b [_reg+0x40] ; Clear P0 + move vr,[_reg+0x41] ; Save special register P1, + clear.w [_reg+0x42] ; Clear P4 + move ccr,[_reg+0x44] ; Save special register CCR + move mof,[_reg+0x46] ; P7 + clear.d [_reg+0x4A] ; Clear P8 + move ibr,[_reg+0x4E] ; P9, + move irp,[_reg+0x52] ; P10, + move srp,[_reg+0x56] ; P11, + move dtp0,[_reg+0x5A] ; P12, register BAR, assembler might not know BAR + ; P13, register DCCR already saved +;; Due to the old assembler-versions BRP might not be recognized + .word 0xE670 ; move brp,r0 + move.d r0,[_reg+0x62] ; Save the return address in BRP + move usp,[_reg+0x66] ; USP + +;; get the serial character (from debugport.c) and check if its a ctrl-c + + jsr _getDebugChar + cmp.b 3, r10 + bne goback + nop + +;; +;; Handle the communication +;; + move.d _internal_stack+1020,sp ; Use the internal stack + moveq 2,r10 ; SIGINT + jsr _handle_exception ; Interactive routine + +goback: +;; +;; Return to the caller +;; + move.d [_reg],r0 ; Restore R0 + move.d [_reg+0x04],r1 ; Restore R1 + move.d [_reg+0x08],r2 ; Restore R2 + move.d [_reg+0x0C],r3 ; Restore R3 + move.d [_reg+0x10],r4 ; Restore R4 + move.d [_reg+0x14],r5 ; Restore R5 + move.d [_reg+0x18],r6 ; Restore R6 + move.d [_reg+0x1C],r7 ; Restore R7 + move.d [_reg+0x20],r8 ; Restore R8 + move.d [_reg+0x24],r9 ; Restore R9 + move.d [_reg+0x28],r10 ; Restore R10 + move.d [_reg+0x2C],r11 ; Restore R11 + move.d [_reg+0x30],r12 ; Restore R12 + move.d [_reg+0x34],r13 ; Restore R13 +;; +;; FIXME: Which registers should be restored? +;; + move.d [_reg+0x38],sp ; Restore SP (R14) + move [_reg+0x56],srp ; Restore the subroutine return pointer. + move [_reg+0x5E],dccr ; Restore DCCR + move [_reg+0x66],usp ; Restore USP + reti ; Return from the interrupt routine + nop +"); + +/* Use this static breakpoint in the start-up only. */ + +void +breakpoint(void) +{ + kgdb_started = 1; + is_dyn_brkp = 0; /* This is a static, not a dynamic breakpoint. */ + __asm__ volatile ("break 8"); /* Jump to handle_breakpoint. */ +} + +/* initialize kgdb. doesn't break into the debugger, but sets up irq and ports */ + +void +kgdb_init(void) +{ + /* could initialize debug port as well but it's done in head.S already... */ + + set_break_vector(8, kgdb_handle_breakpoint); + set_int_vector(8, kgdb_handle_serial, 0); + + enableDebugIRQ(); +} + +/****************************** End of file **********************************/ diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/ksyms.c linux/arch/cris/kernel/ksyms.c --- v2.4.1/linux/arch/cris/kernel/ksyms.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/ksyms.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,2 @@ +/* no kernel support yet */ + diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c --- v2.4.1/linux/arch/cris/kernel/process.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/process.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,327 @@ +/* $Id: process.c,v 1.8 2000/09/13 14:34:13 bjornw Exp $ + * + * linux/arch/cris/kernel/process.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 2000 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +//#define DEBUG + +/* + * Initial task structure. Make this a per-architecture thing, + * because different architectures tend to have different + * alignment requirements and potentially different initial + * setup. + */ + +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 having a special + * "init_task" linker map entry.. + */ + +union task_union init_task_union + __attribute__((__section__(".data.init_task"))) = + { INIT_TASK(init_task_union.task) }; + +static int hlt_counter=0; + +/* in a system call, set_esp0 is called to remember the stack frame, therefore + in the implementation of syscalls we can use that value to access the stack + frame and saved registers. +*/ + +#define currentregs ((struct pt_regs *)current->thread.esp0) + +asmlinkage void set_esp0(unsigned long ssp) +{ + current->thread.esp0 = ssp; +} + +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + +int cpu_idle(void *unused) +{ + while(1) { + current->counter = -100; + schedule(); + } +} + +/* if the watchdog is enabled, we can simply disable interrupts and go + * into an eternal loop, and the watchdog will reset the CPU after 0.1s + */ + +void hard_reset_now (void) +{ + printk("*** HARD RESET ***\n"); + cli(); + while(1) /* waiting for RETRIBUTION! */ ; +} + +void machine_restart(void) +{ + hard_reset_now(); +} + +/* can't do much here... */ + +void machine_halt(void) +{ +} + +void machine_power_off(void) +{ +} + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + */ + +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + register long __a __asm__ ("r10"); + + __asm__ __volatile__ + ("movu.w %1,r1\n\t" /* r1 contains syscall number, to sys_clone */ + "clear.d r10\n\t" /* r10 is argument 1 to clone */ + "move.d %2,r11\n\t" /* r11 is argument 2 to clone, the flags */ + "break 13\n\t" /* call sys_clone, this will fork */ + "test.d r10\n\t" /* parent or child? child returns 0 here. */ + "bne 1f\n\t" /* jump if parent */ + "nop\n\t" /* delay slot */ + "move.d %4,r10\n\t" /* set argument to function to call */ + "jsr %5\n\t" /* call specified function */ + "movu.w %3,r1\n\t" /* r1 is sys_exit syscall number */ + "moveq -1,r10\n\t" /* Give a really bad exit-value */ + "break 13\n\t" /* call sys_exit, killing the child */ + "1:\n\t" + : "=r" (__a) + : "g" (__NR_clone), "r" (flags | CLONE_VM), "g" (__NR_exit), + "r" (arg), "r" (fn) + : "r10", "r11", "r1"); + + return __a; +} + + + +void flush_thread(void) +{ +} + +asmlinkage void ret_from_sys_call(void); + +/* setup the child's kernel stack with a pt_regs and switch_stack on it. + * it will be un-nested during _resume and _ret_from_sys_call when the + * new thread is scheduled. + * + * also setup the thread switching structure which is used to keep + * thread-specific data during _resumes. + * + */ + +int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct *p, struct pt_regs *regs) +{ + struct pt_regs * childregs; + struct switch_stack *swstack; + + /* put the pt_regs structure at the end of the new kernel stack page and fix it up + * remember that the task_struct doubles as the kernel stack for the task + */ + + childregs = ((struct pt_regs *) ((unsigned long)p + THREAD_SIZE)) - 1; + + *childregs = *regs; /* struct copy of pt_regs */ + + childregs->r10 = 0; /* child returns 0 after a fork/clone */ + + /* put the switch stack right below the pt_regs */ + + swstack = ((struct switch_stack *)childregs) - 1; + + swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ + + /* we want to return into ret_from_sys_call after the _resume */ + + swstack->return_ip = (unsigned long) ret_from_sys_call; + + /* fix the user-mode stackpointer */ + + p->thread.usp = usp; + + /* and the kernel-mode one */ + + p->thread.ksp = (unsigned long) swstack; + + /* esp0 keeps the pt_regs stacked structure pointer */ + + p->thread.esp0 = (unsigned long) childregs; + +#ifdef DEBUG + printk("kern_stack_page 0x%x, used stack %d, thread.usp 0x%x, usp 0x%x\n", + current->kernel_stack_page, usedstack, p->thread.usp, usp); +#endif + return 0; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + int i; +#if 0 +/* changed the size calculations - should hopefully work better. lbt */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + for (i = 0; i < 8; i++) + dump->u_debugreg[i] = current->debugreg[i]; + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; + + dump->regs = *regs; + + dump->u_fpvalid = dump_fpu (regs, &dump->i387); +#endif +} + +asmlinkage int sys_fork(void) +{ + return do_fork(SIGCHLD, rdusp(), currentregs, 0); +} + +/* if newusp is 0, we just grab the old usp */ + +asmlinkage int sys_clone(unsigned long newusp, unsigned long flags) +{ + if (!newusp) + newusp = rdusp(); + return do_fork(flags, newusp, currentregs, 0); +} + +/* vfork is a system call in i386 because of register-pressure - maybe + * we can remove it and handle it in libc but we put it here until then. + */ + +asmlinkage int sys_vfork(void) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), currentregs, 0); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(const char *fname, char **argv, char **envp) +{ + int error; + char *filename; + + filename = getname(fname); + error = PTR_ERR(filename); + + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, currentregs); + putname(filename); + out: + return error; +} + +/* + * 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) +{ +#if 0 + /* YURGH. TODO. */ + + unsigned long ebp, esp, eip; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + stack_page = (unsigned long)p; + esp = p->thread.esp; + if (!stack_page || esp < stack_page || esp > 8188+stack_page) + return 0; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + ebp = *(unsigned long *) esp; + do { + if (ebp < stack_page || ebp > 8184+stack_page) + return 0; + eip = *(unsigned long *) (ebp+4); + if (eip < first_sched || eip >= last_sched) + return eip; + ebp = *(unsigned long *) ebp; + } while (count++ < 16); +#endif + return 0; +} +#undef last_sched +#undef first_sched diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/ptrace.c linux/arch/cris/kernel/ptrace.c --- v2.4.1/linux/arch/cris/kernel/ptrace.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/ptrace.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,340 @@ +/* + * linux/arch/cris/kernel/ptrace.c + * + * Parts taken from the m68k port. + * + * Copyright (c) 2000 Axis Communications AB + * + * Authors: Bjorn Wesen + * + * $Log: ptrace.c,v $ + * Revision 1.3 2000/12/18 23:45:25 bjornw + * Linux/CRIS first version + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which bits in DCCR the user has access to. */ +/* 1 = access 0 = no access */ +#define DCCR_MASK 0x0000001f /* XNZVC */ + +/* + * Get contents of register REGNO in task TASK. + */ +static inline long get_reg(struct task_struct *task, unsigned int regno) +{ + /* USP is a special case, it's not in the pt_regs struct but + * in the tasks thread struct + */ + + if (regno == PT_USP) + return task->thread.usp; + else if (regno <= PT_MAX) + return ((unsigned long *)(task->thread.esp0))[regno]; + else + return 0; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, unsigned int regno, + unsigned long data) +{ + unsigned long *addr; + + if (regno == PT_USP) + task->thread.usp = data; + else if (regno <= PT_MAX) + ((unsigned long *)(task->thread.esp0))[regno] = data; + else + return -1; + return 0; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out_tsk; + if (request == PTRACE_ATTACH) { + if (child == current) + goto out_tsk; + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->suid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out_tsk; + /* the same process cannot be attached many times */ + if (child->ptrace & PT_PTRACED) + goto out_tsk; + child->ptrace |= PT_PTRACED; + + write_lock_irq(&tasklist_lock); + if (child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + write_unlock_irq(&tasklist_lock); + + send_sig(SIGSTOP, child, 1); + ret = 0; + goto out_tsk; + } + ret = -ESRCH; + if (!(child->ptrace & PT_PTRACED)) + goto out_tsk; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out_tsk; + } + if (child->p_pptr != current) + goto out_tsk; + + switch (request) { + /* when I and D space are separate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + if (copied != sizeof(tmp)) + break; + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) + break; + + tmp = 0; /* Default return condition */ + ret = -EIO; + if (addr < sizeof(struct pt_regs)) { + tmp = get_reg(child, addr >> 2); + ret = put_user(tmp, (unsigned long *)data); + } + break; + } + + /* when I and D space are separate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = 0; + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + break; + ret = -EIO; + break; + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; + if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) + break; + + if (addr < sizeof(struct pt_regs)) { + addr >>= 2; + + if (addr == PT_DCCR) { + /* don't allow the tracing process to change stuff like + * interrupt enable, kernel/user bit, dma enables etc. + */ + data &= DCCR_MASK; + data |= get_reg(child, PT_DCCR) & ~DCCR_MASK; + } + if (put_reg(child, addr, data)) + break; + ret = 0; + } + break; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: { /* restart after signal. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + child->ptrace |= PT_TRACESYS; + else + child->ptrace &= ~PT_TRACESYS; + child->exit_code = data; + /* TODO: make sure any pending breakpoint is killed */ + wake_up_process(child); + ret = 0; + break; + } + +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + long tmp; + + ret = 0; + if (child->state == TASK_ZOMBIE) /* already dead */ + break; + child->exit_code = SIGKILL; + /* TODO: make sure any pending breakpoint is killed */ + wake_up_process(child); + break; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->ptrace &= ~PT_TRACESYS; + + /* TODO: set some clever breakpoint mechanism... */ + + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_DETACH: { /* detach a process that was attached. */ + long tmp; + + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->ptrace &= ~(PT_PTRACED | PT_TRACESYS); + child->exit_code = data; + write_lock_irq(&tasklist_lock); + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + write_unlock_irq(&tasklist_lock); + /* TODO: make sure any pending breakpoint is killed */ + wake_up_process(child); + ret = 0; + break; + } + + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + int i; + unsigned long tmp; + for (i = 0; i <= PT_MAX; i++) { + tmp = get_reg(child, i); + if (put_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + break; + } + data += sizeof(long); + } + ret = 0; + break; + } + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + int i; + unsigned long tmp; + for (i = 0; i <= PT_MAX; i++) { + if (get_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + break; + } + if (i == PT_DCCR) { + tmp &= DCCR_MASK; + tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK; + } + put_reg(child, i, tmp); + data += sizeof(long); + } + ret = 0; + break; + } + + default: + ret = -EIO; + break; + } +out_tsk: + free_task_struct(child); +out: + unlock_kernel(); + return ret; +} + +asmlinkage void syscall_trace(void) +{ + if ((current->ptrace & (PT_PTRACED | PT_TRACESYS)) != + (PT_PTRACED | PT_TRACESYS)) + return; + /* TODO: make a way to distinguish between a syscall stop and SIGTRAP + * delivery like in the i386 port ? + */ + 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.4.1/linux/arch/cris/kernel/semaphore.c linux/arch/cris/kernel/semaphore.c --- v2.4.1/linux/arch/cris/kernel/semaphore.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/semaphore.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,238 @@ +/* + * 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); + 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); + 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.4.1/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c --- v2.4.1/linux/arch/cris/kernel/setup.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/setup.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,264 @@ +/* $Id: setup.c,v 1.8 2001/01/16 16:31:38 bjornw Exp $ + * + * linux/arch/cris/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (c) 2000 Axis Communications AB + */ + +/* + * This file handles the architecture-dependent parts of initialization + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Setup options + */ +struct drive_info_struct { char dummy[32]; } drive_info; +struct screen_info screen_info; + +unsigned char aux_device_present; + +#ifdef CONFIG_BLK_DEV_RAM +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ +#endif + +extern int root_mountflags; +extern char _etext, _edata, _end; + +#define COMMAND_LINE_SIZE 256 + +static char command_line[COMMAND_LINE_SIZE] = { 0, }; + char saved_command_line[COMMAND_LINE_SIZE]; + +extern const unsigned long text_start, edata; /* set by the linker script */ + +extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* from head.S */ + +/* This mainly sets up the memory area, and can be really confusing. + * + * The physical DRAM is virtually mapped into dram_start to dram_end + * (usually c0000000 to c0000000 + DRAM size). The physical address is + * given by the macro __pa(). + * + * In this DRAM, the kernel code and data is loaded, in the beginning. + * It really starts at c00a0000 to make room for some special pages - + * the start address is text_start. The kernel data ends at _end. After + * this the ROM filesystem is appended (if there is any). + * + * Between this address and dram_end, we have RAM pages usable to the + * boot code and the system. + * + */ + +void __init setup_arch(char **cmdline_p) +{ + unsigned long bootmap_size; + unsigned long start_pfn, max_pfn; + unsigned long memory_start; + extern void console_print_etrax(const char *b); + +#if (defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)) + /* TODO: move this into flash_init I think */ + flash_probe(); +#endif + + /* register an initial console printing routine for printk's */ + + init_etrax_debug(); + + /* we should really poll for DRAM size! */ + + high_memory = &dram_end; + + if(romfs_in_flash || !romfs_length) { + /* if we have the romfs in flash, or if there is no rom filesystem, + * our free area starts directly after the BSS + */ + memory_start = (unsigned long) &_end; + } else { + /* otherwise the free area starts after the ROM filesystem */ + printk("ROM fs in RAM, size %d bytes\n", romfs_length); + memory_start = romfs_start + romfs_length; + } + + /* process 1's initial memory region is the kernel code/data */ + + init_mm.start_code = (unsigned long) &text_start; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + + /* min_low_pfn points to the start of DRAM, start_pfn points + * to the first DRAM pages after the kernel, and max_low_pfn + * to the end of DRAM. + */ + + /* + * partially used pages are not usable - thus + * we are rounding upwards: + */ + + start_pfn = PFN_UP(memory_start); /* usually c0000000 + kernel + romfs */ + max_pfn = PFN_DOWN((unsigned long)high_memory); /* usually c0000000 + dram size */ + + /* + * Initialize the boot-time allocator (start, end) + * + * We give it access to all our DRAM, but we could as well just have + * given it a small slice. No point in doing that though, unless we + * have non-contiguous memory and want the boot-stuff to be in, say, + * the smallest area. + * + * It will put a bitmap of the allocated pages in the beginning + * of the range we give it, but it won't mark the bitmaps pages + * as reserved. We have to do that ourselves below. + * + * We need to use init_bootmem_node instead of init_bootmem + * because our map starts at a quite high address (min_low_pfn). + */ + + max_low_pfn = max_pfn; + min_low_pfn = PAGE_OFFSET >> PAGE_SHIFT; + + bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn, + min_low_pfn, + max_low_pfn); + + /* And free all memory not belonging to the kernel (addr, size) */ + + free_bootmem(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn - start_pfn)); + + /* + * Reserve the bootmem bitmap itself as well. We do this in two + * steps (first step was init_bootmem()) because this catches + * the (very unlikely) case of us accidentally initializing the + * bootmem allocator with an invalid RAM area. + * + * Arguments are start, size + */ + + reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size); + + /* paging_init() sets up the MMU and marks all pages as reserved */ + + paging_init(); + + /* we dont use a command line yet, so just let it be an empty string */ + + *cmdline_p = command_line; + strcpy(command_line, "root=/dev/rom"); /* use the appended romdisk as root */ + + /* give credit for the CRIS port */ + + printk("Linux/CRIS port on ETRAX 100LX (c) 2000 Axis Communications AB\n"); + +} + +#ifdef CONFIG_PROC_FS +#define HAS_FPU 0x0001 +#define HAS_MMU 0x0002 +#define HAS_ETHERNET100 0x0004 +#define HAS_TOKENRING 0x0008 +#define HAS_SCSI 0x0010 +#define HAS_ATA 0x0020 +#define HAS_USB 0x0040 +#define HAS_IRQ_BUG 0x0080 + +static struct cpu_info { + char *model; + unsigned short cache; + unsigned short flags; +} cpu_info[] = { + { "ETRAX 1", 0, 0 }, + { "ETRAX 2", 0, 0 }, /* Don't say it HAS_TOKENRING - there are + lethal bugs in that chip that + prevents T-R from ever working. + Never go there, and never lead anyone + into believing it can work. BTW: + Anyone working on a T-R network + driver? :-) :-) :-) :-/ */ + { "ETRAX 3", 0, HAS_TOKENRING }, + { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, + { "Unknown", 0, 0 }, + { "Unknown", 0, 0 }, + { "Unknown", 0, 0 }, + { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, + { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, + { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, + { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, + { "Unknown", 0, 0 }, +}; + +/* + * BUFFER is PAGE_SIZE bytes long. + */ +int get_cpuinfo(char *buffer) +{ + int revision; +#ifndef CONFIG_SVINTO_SIM + unsigned char tmp; + + __asm__ volatile ("move vr,%0" : "=rm" (tmp)); + revision = tmp; +#else + /* Fake a revision for the simulator */ + revision = 7; +#endif + + return sprintf(buffer, + "cpu\t\t: CRIS\n" + "cpu revision\t: %d\n" + "cpu model\t: %s\n" + "cache size\t: %d kB\n" + "fpu\t\t: %s\n" + "mmu\t\t: %s\n" + "ethernet\t: %s Mbps\n" + "token ring\t: %s\n" + "scsi\t\t: %s\n" + "ata\t\t: %s\n" + "usb\t\t: %s\n" + "bogomips\t: %lu.%02lu\n", + + revision, + cpu_info[revision].model, + cpu_info[revision].cache, + cpu_info[revision].flags & HAS_FPU ? "yes" : "no", + cpu_info[revision].flags & HAS_MMU ? "yes" : "no", + cpu_info[revision].flags & HAS_ETHERNET100 ? "10/100" : "10", + cpu_info[revision].flags & HAS_TOKENRING ? "4/16 Mbps" : "no", + cpu_info[revision].flags & HAS_SCSI ? "yes" : "no", + cpu_info[revision].flags & HAS_ATA ? "yes" : "no", + cpu_info[revision].flags & HAS_USB ? "yes" : "no", + (loops_per_jiffy * HZ + 500) / 100000, + ((loops_per_jiffy * HZ + 500) / 1000) % 100); +} +#endif /* CONFIG_PROC_FS */ diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/shadows.c linux/arch/cris/kernel/shadows.c --- v2.4.1/linux/arch/cris/kernel/shadows.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/shadows.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,20 @@ +/* $Id: shadows.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $ + * + * Various Etrax shadow registers. Defines for these are in include/asm-etrax100/io.h + */ + +#include + +unsigned long genconfig_shadow = 42; +unsigned long port_g_data_shadow = 42; +unsigned char port_pa_dir_shadow = 42; +unsigned char port_pa_data_shadow = 42; +unsigned char port_pb_i2c_shadow = 42; +unsigned char port_pb_config_shadow = 42; +unsigned char port_pb_dir_shadow = 42; +unsigned char port_pb_data_shadow = 42; +unsigned long r_timer_ctrl_shadow = 42; + +#ifdef CONFIG_ETRAX_90000000_LEDS +unsigned long port_90000000_shadow = 42; +#endif diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/signal.c linux/arch/cris/kernel/signal.c --- v2.4.1/linux/arch/cris/kernel/signal.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/signal.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,667 @@ +/* + * linux/arch/cris/kernel/signal.c + * + * Based on arch/i386/kernel/signal.c by + * Copyright (C) 1991, 1992 Linus Torvalds + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * + * + * Ideas also taken from arch/arm. + * + * Copyright (C) 2000 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DEBUG_SIG 0 + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +/* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */ +/* manipulate regs so that upon return, it will be re-executed */ + +#define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2; + +int sys_wait4(pid_t pid, unsigned long *stat_addr, + int options, unsigned long *ru); + +int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); + +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ +int +sys_sigsuspend(old_sigset_t mask) +{ + struct pt_regs * regs = (struct pt_regs *)current_regs(); + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->r10 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(0, &saveset, regs)) + return -EINTR; + } +} + +int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) +{ + struct pt_regs * regs = (struct pt_regs *)current_regs(); + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + regs->r10 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(0, &saveset, regs)) + return -EINTR; + } +} + +int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +int +sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + return do_sigaltstack(uss, uoss, rdusp()); +} + + +/* + * Do a signal return; undo the signal stack. + */ + +struct sigframe { + struct sigcontext sc; + unsigned long extramask[_NSIG_WORDS-1]; + unsigned char retcode[8]; /* trampoline code */ +}; + +struct rt_sigframe { + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + unsigned char retcode[8]; /* trampoline code */ +}; + + +static int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +{ + unsigned int err = 0; + unsigned long old_usp; + + /* restore the regs from &sc->regs (same as sc, since regs is first) + * (sc is already checked for VERIFY_READ since the sigframe was + * checked in sys_sigreturn previously) + */ + + if (__copy_from_user(regs, sc, sizeof(struct pt_regs))) + goto badframe; + + /* make sure the U-flag is set so user-mode cannot fool us */ + + regs->dccr |= 1 << 8; + + /* restore the old USP as it was before we stacked the sc etc. + * (we cannot just pop the sigcontext since we aligned the sp and + * stuff after pushing it) + */ + + err |= __get_user(old_usp, &sc->usp); + + wrusp(old_usp); + + /* TODO: the other ports use regs->orig_XX to disable syscall checks + * after this completes, but we don't use that mechanism. maybe we can + * use it now ? + */ + + return err; + +badframe: + return 1; +} + +asmlinkage int sys_sigreturn(void) +{ + struct pt_regs *regs = (struct pt_regs *)current_regs(); + struct sigframe *frame = (struct sigframe *)rdusp(); + sigset_t set; + + /* + * Since we stacked the signal on a dword boundary, + * then frame should be dword aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (((long)frame) & 3) + goto badframe; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + 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(regs, &frame->sc)) + goto badframe; + + /* TODO: SIGTRAP when single-stepping as in arm ? */ + + return regs->r10; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int sys_rt_sigreturn(void) +{ + struct pt_regs *regs = (struct pt_regs *)current_regs(); + struct rt_sigframe *frame = (struct rt_sigframe *)rdusp(); + sigset_t set; + stack_t st; + + /* + * Since we stacked the signal on a dword boundary, + * then frame should be dword aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (((long)frame) & 3) + goto badframe; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) + goto badframe; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, rdusp()); + + return regs->r10; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +/* + * Set up a signal frame. + */ + +static int +setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask) +{ + int err = 0; + unsigned long usp = rdusp(); + + /* copy the regs. they are first in sc so we can use sc directly */ + + err |= __copy_to_user(sc, regs, sizeof(struct pt_regs)); + + /* then some other stuff */ + + err |= __put_user(mask, &sc->oldmask); + + err |= __put_user(usp, &sc->usp); + + return err; +} + +/* figure out where we want to put the new signal frame - usually on the stack */ + +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) +{ + unsigned long sp = rdusp(); + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + } + + /* make sure the frame is dword-aligned */ + + sp &= ~3; + + return (void *)(sp - frame_size); +} + +/* grab and setup a signal frame. + * + * basically we stack a lot of state info, and arrange for the + * user-mode program to return to the kernel using either a + * trampoline which performs the syscall sigreturn, or a provided + * user-mode trampoline. + */ + +static void setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs * regs) +{ + struct sigframe *frame; + unsigned long return_ip; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); + if (err) + goto give_sigsegv; + + if (_NSIG_WORDS > 1) { + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + } + if (err) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + return_ip = (unsigned long)ka->sa.sa_restorer; + } else { + /* trampoline - the desired return ip is the retcode itself */ + return_ip = (unsigned long)&frame->retcode; + /* This is movu.w __NR_sigreturn, r1; break 13; */ + /* TODO: check byteorder */ + err |= __put_user(0x1c5f, (short *)(frame->retcode+0)); + err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); + err |= __put_user(0xe93d, (short *)(frame->retcode+4)); + } + + if (err) + goto give_sigsegv; + + /* Set up registers for signal handler */ + + regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ + regs->srp = return_ip; /* what we enter LATER */ + + /* actually move the usp to reflect the stacked frame */ + + wrusp((unsigned long)frame); + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs * regs) +{ + struct rt_sigframe *frame; + unsigned long return_ip; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto give_sigsegv; + + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + if (err) + goto give_sigsegv; + + /* Clear all the bits of the ucontext we don't use. */ + err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); + + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + if (err) + goto give_sigsegv; + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + return_ip = (unsigned long)ka->sa.sa_restorer; + } else { + /* trampoline - the desired return ip is the retcode itself */ + return_ip = (unsigned long)&frame->retcode; + /* This is movu.w __NR_sigreturn, r1; break 13; */ + /* TODO: check byteorder */ + err |= __put_user(0x1c5f, (short *)(frame->retcode+0)); + err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2)); + err |= __put_user(0xe93d, (short *)(frame->retcode+4)); + } + + if (err) + goto give_sigsegv; + + /* TODO what is the current->exec_domain stuff and invmap ? */ + + /* Set up registers for signal handler */ + + regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ + regs->srp = return_ip; /* what we enter LATER */ + + /* actually move the usp to reflect the stacked frame */ + + wrusp((unsigned long)frame); + + return; + +give_sigsegv: + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, current); +} + +/* + * OK, we're invoking a handler + */ + +static inline void +handle_signal(int canrestart, unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) +{ + /* Are we from a system call? */ + if (canrestart) { + /* If so, check system call restarting.. */ + switch (regs->r10) { + case -ERESTARTNOHAND: + /* ERESTARTNOHAND means that the syscall should only be + restarted if there was no handler for the signal, and since + we only get here if there is a handler, we dont restart */ + regs->r10 = -EINTR; + break; + + case -ERESTARTSYS: + /* ERESTARTSYS means to restart the syscall if there is no + handler or the handler was registered with SA_RESTART */ + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->r10 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + /* ERESTARTNOINTR means that the syscall should be called again + after the signal handler returns. */ + RESTART_CRIS_SYS(regs); + } + } + + /* Set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); + + 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); + } +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + */ +int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) +{ + siginfo_t info; + struct k_sigaction *ka; + + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 1; + + 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->ptrace & PT_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ + current->exit_code = signr; + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + + /* We're back. Did the debugger cancel the sig? */ + if (!(signr = current->exit_code)) + continue; + current->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ + if (signr == SIGSTOP) + continue; + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); + continue; + } + } + + ka = ¤t->sig->action[signr-1]; + if (ka->sa.sa_handler == SIG_IGN) { + if (signr != SIGCHLD) + continue; + /* Check for SIGCHLD: it's special. */ + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) + /* nothing */; + continue; + } + + if (ka->sa.sa_handler == SIG_DFL) { + int exit_code = signr; + + /* Init gets no signals it doesn't want. */ + if (current->pid == 1) + continue; + + switch (signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + /* FALLTHRU */ + + case SIGSTOP: + current->state = TASK_STOPPED; + current->exit_code = signr; + if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) + notify_parent(current, SIGCHLD); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGABRT: case SIGFPE: case SIGSEGV: + case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: + if (do_coredump(signr, regs)) + exit_code |= 0x80; + /* FALLTHRU */ + + default: + lock_kernel(); + sigaddset(¤t->pending.signal, signr); + recalc_sigpending(current); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + /* Whee! Actually deliver the signal. */ + handle_signal(canrestart, signr, ka, &info, oldset, regs); + return 1; + } + + /* Did we come from a system call? */ + if (canrestart) { + /* Restart the system call - no handlers present */ + if (regs->r10 == -ERESTARTNOHAND || + regs->r10 == -ERESTARTSYS || + regs->r10 == -ERESTARTNOINTR) { + RESTART_CRIS_SYS(regs); + } + } + return 0; +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c --- v2.4.1/linux/arch/cris/kernel/sys_cris.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/sys_cris.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,201 @@ +/* $Id: sys_cris.c,v 1.3 2000/08/02 13:59:02 bjornw Exp $ + * + * linux/arch/cris/kernel/sys_etrax.c + * + * This file contains various random system calls that + * have a non-standard calling sequence on some platforms. + * Since we don't have to do any backwards compatibility, our + * versions are done in the most "normal" way possible. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way Unix traditionally does this, though. + */ +asmlinkage int sys_pipe(unsigned long * fildes) +{ + int fd[2]; + int error; + + lock_kernel(); + error = do_pipe(fd); + unlock_kernel(); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +/* sys_mmap used to take a ptr to a buffer instead containing the args + * but we support syscalls with 6 arguments now + */ + +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; + int ret = -EBADF; + + lock_kernel(); + if (!(flags & MAP_ANONYMOUS)) { + if (!(file = fget(fd))) + goto out; + } + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + down(¤t->mm->mmap_sem); + ret = do_mmap(file, addr, len, prot, flags, offset); + up(¤t->mm->mmap_sem); + if (file) + fput(file); + out: + unlock_kernel(); + return ret; +} + +/* 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; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + 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: + return error; +} + +asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot, + int flags, int fd, off_t offset) +{ + return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); +} + +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); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. (same as arch/i386) + */ + +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; + } +} + +/* apparently this is legacy - if we don't need this in Linux/CRIS we can remove it. */ + +asmlinkage int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/time.c linux/arch/cris/kernel/time.c --- v2.4.1/linux/arch/cris/kernel/time.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/time.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,453 @@ +/* $Id: time.c,v 1.4 2000/10/17 14:44:58 bjornw Exp $ + * + * linux/arch/cris/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Copyright (C) 1999, 2000 Axis Communications AB + * + * 1994-07-02 Alan Modra + * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime + * 1995-03-26 Markus Kuhn + * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 + * precision CMOS clock update + * 1996-05-03 Ingo Molnar + * fixed time warps in do_[slow|fast]_gettimeoffset() + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + * + * Linux/CRIS specific code: + * + * Authors: Bjorn Wesen + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +static int have_rtc; /* used to remember if we have an RTC or not */ + +/* define this if you need to use print_timestamp */ +/* it will make jiffies at 96 hz instead of 100 hz though */ +#undef USE_CASCADE_TIMERS + +extern int setup_etrax_irq(int, struct irqaction *); + +#define TICK_SIZE tick + +static unsigned long do_slow_gettimeoffset(void) +{ + unsigned long count; + + static unsigned long count_p = LATCH; /* for the first call after boot */ + static unsigned long jiffies_p = 0; + + /* + * cache volatile jiffies temporarily; we have IRQs turned off. + */ + unsigned long jiffies_t; + + /* The timer interrupt comes from Etrax timer 0. In order to get + * better precision, we check the current value. It might have + * underflowed already though. + */ + +#ifndef CONFIG_SVINTO_SIM + /* Not available in the xsim simulator. */ + count = *R_TIMER0_DATA; +#else + count = 0; +#endif + + jiffies_t = jiffies; + + /* + * avoiding timer inconsistencies (they are rare, but they happen)... + * there are three kinds of problems that must be avoided here: + * 1. the timer counter underflows + * 2. hardware problem with the timer, not giving us continuous time, + * the counter does small "jumps" upwards on some Pentium systems, + * thus causes time warps + * 3. we are after the timer interrupt, but the bottom half handler + * hasn't executed yet. + */ + if( jiffies_t == jiffies_p ) { + if( count > count_p ) { + } + } else + jiffies_p = jiffies_t; + + count_p = count; + + count = ((LATCH-1) - count) * TICK_SIZE; + count = (count + LATCH/2) / LATCH; + + return count; +} + +static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; + +/* + * This version of gettimeofday has near microsecond resolution. + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + save_flags(flags); + cli(); + *tv = xtime; + tv->tv_usec += do_gettimeoffset(); + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } + restore_flags(flags); +} + +void do_settimeofday(struct timeval *tv) +{ + cli(); + /* This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ + tv->tv_usec -= do_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime = *tv; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_state = TIME_ERROR; /* p. 24, (a) */ + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + sti(); +} + + +/* + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you'll only notice that after reboot! + */ + +static int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + printk("set_rtc_mmss(%d)\n", nowtime); + + if(!have_rtc) + return 0; + + cmos_minutes = CMOS_READ(RTC_MINUTES); + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + return retval; +} + +/* Except from the Etrax100 HSDD about the built-in watchdog: + * + * 3.10.4 Watchdog timer + + * When the watchdog timer is started, it generates an NMI if the watchdog + * isn't restarted or stopped within 0.1 s. If it still isn't restarted or + * stopped after an additional 3.3 ms, the watchdog resets the chip. + * The watchdog timer is stopped after reset. The watchdog timer is controlled + * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit + * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is + * described in the table below: + * + * Watchdog Value written: + * state: To enable: To key: Operation: + * -------- ---------- ------- ---------- + * stopped 0 X No effect. + * stopped 1 key_val Start watchdog with key = key_val. + * started 0 ~key Stop watchdog + * started 1 ~key Restart watchdog with key = ~key. + * started X new_key_val Change key to new_key_val. + * + * Note: '~' is the bitwise NOT operator. + * + */ + +/* right now, starting the watchdog is the same as resetting it */ +#define start_watchdog reset_watchdog + +static int watchdog_key = 0; /* arbitrary number */ + +/* number of pages to consider "out of memory". it is normal that the memory + * is used though, so put this really low. + */ + +#define WATCHDOG_MIN_FREE_PAGES 8 + +extern int nr_free_pages; + +static inline void +reset_watchdog(void) +{ +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) + /* only keep watchdog happy as long as we have memory left! */ + if(nr_free_pages > WATCHDOG_MIN_FREE_PAGES) { + /* reset the watchdog with the inverse of the old key */ + watchdog_key ^= 0x7; /* invert key, which is 3 bits */ + *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | + IO_STATE(R_WATCHDOG, enable, start); + } +#endif +} + +/* last time the cmos clock got updated */ +static long last_rtc_update = 0; + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ + +//static unsigned short myjiff; /* used by our debug routine print_timestamp */ + +static inline void +timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* acknowledge the timer irq */ + +#ifdef USE_CASCADE_TIMERS + *R_TIMER_CTRL = + IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | + IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | + IO_STATE( R_TIMER_CTRL, i1, clr) | + IO_STATE( R_TIMER_CTRL, tm1, run) | + IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | + IO_STATE( R_TIMER_CTRL, i0, clr) | + IO_STATE( R_TIMER_CTRL, tm0, run) | + IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); +#else + *R_TIMER_CTRL = r_timer_ctrl_shadow | + IO_STATE(R_TIMER_CTRL, i0, clr); +#endif + + /* reset watchdog otherwise it resets us! */ + + reset_watchdog(); + + /* call the real timer interrupt handler */ + + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + + if ((time_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; + +} + +#if 0 +/* some old debug code for testing the microsecond timing of packets */ +static unsigned int lastjiff; + +void print_timestamp(const char *s) +{ + unsigned long flags; + unsigned int newjiff; + save_flags(flags); + cli(); + newjiff = (myjiff << 16) | (unsigned short)(-*R_TIMER01_DATA); + printk("%s: %x (%x)\n", s, newjiff, newjiff - lastjiff); + lastjiff = newjiff; + restore_flags(flags); +} +#endif + +/* grab the time from the RTC chip */ + +unsigned long +get_cmos_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + int i; + + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + + printk("rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n", + sec, min, hour, day, mon, year); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + + if ((year += 1900) < 1970) + year += 100; + + return mktime(year, mon, day, hour, min, sec); +} + +/* update xtime from the CMOS settings. used when /dev/rtc gets a SET_TIME. + * TODO: this doesn't reset the fancy NTP phase stuff as do_settimeofday does. + */ + +void +update_xtime_from_cmos(void) +{ + if(have_rtc) { + xtime.tv_sec = get_cmos_time(); + xtime.tv_usec = 0; + } +} + +/* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain + * it needs to be SA_INTERRUPT to make the jiffies update work properly + */ + +static struct irqaction irq2 = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT, + 0, "timer", NULL, NULL}; + +void __init +time_init(void) +{ + /* probe for the RTC and read it if it exists */ + + if(RTC_INIT() < 0) { + /* no RTC, start at 1980 */ + xtime.tv_sec = 0; + xtime.tv_usec = 0; + have_rtc = 0; + } else { + /* get the current time */ + have_rtc = 1; + update_xtime_from_cmos(); + } + + /* Setup the etrax timers + * Base frequency is 19200 hz, divider 192 -> 100 hz as Linux wants + * In normal mode, we use timer0, so timer1 is free. In cascade + * mode (which we sometimes use for debugging) both timers are used. + * Remember that linux/timex.h contains #defines that rely on the + * timer settings below (hz and divide factor) !!! + */ + +#ifdef USE_CASCADE_TIMERS + *R_TIMER_CTRL = + IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | + IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | + IO_STATE( R_TIMER_CTRL, i1, nop) | + IO_STATE( R_TIMER_CTRL, tm1, stop_ld) | + IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | + IO_STATE( R_TIMER_CTRL, i0, nop) | + IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | + IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); + + *R_TIMER_CTRL = r_timer_ctrl_shadow = + IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | + IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | + IO_STATE( R_TIMER_CTRL, i1, nop) | + IO_STATE( R_TIMER_CTRL, tm1, run) | + IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | + IO_STATE( R_TIMER_CTRL, i0, nop) | + IO_STATE( R_TIMER_CTRL, tm0, run) | + IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); +#else + *R_TIMER_CTRL = + IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | + IO_FIELD(R_TIMER_CTRL, timerdiv0, 192) | + IO_STATE(R_TIMER_CTRL, i1, nop) | + IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | + IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | + IO_STATE(R_TIMER_CTRL, i0, nop) | + IO_STATE(R_TIMER_CTRL, tm0, stop_ld) | + IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz); + + *R_TIMER_CTRL = r_timer_ctrl_shadow = + IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | + IO_FIELD(R_TIMER_CTRL, timerdiv0, 192) | + IO_STATE(R_TIMER_CTRL, i1, nop) | + IO_STATE(R_TIMER_CTRL, tm1, run) | + IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | + IO_STATE(R_TIMER_CTRL, i0, nop) | + IO_STATE(R_TIMER_CTRL, tm0, run) | + IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz); +#endif + + *R_IRQ_MASK0_SET = + IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ + + /* now actually register the timer irq handler that calls timer_interrupt() */ + + setup_etrax_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ + + /* enable watchdog if we should use one */ + +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) + printk("Enabling watchdog...\n"); + start_watchdog(); +#endif + +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c --- v2.4.1/linux/arch/cris/kernel/traps.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/kernel/traps.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,167 @@ +/* $Id: traps.c,v 1.3 2000/10/04 16:50:06 bjornw Exp $ + * + * linux/arch/cris/traps.c + * + * Etrax100 does not have any hardware traps, only IRQ's, which we setup + * in irq.c instead. Here we just define the die_if_kernel Oops'er. + * + * Copyright (C) 2000 Axis Communications AB + * + * Authors: Bjorn Wesen + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +int kstack_depth_to_print = 24; + +/* + * These constants are 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) + +void show_stack(unsigned long *sp) +{ + unsigned long *stack, addr, module_start, module_end; + int i; + extern char _stext, _etext; + + // debugging aid: "show_stack(NULL);" prints the + // back trace for this cpu. + + if(sp == NULL) + sp = (unsigned long*)rdsp(); + + stack = sp; + + for(i = 0; i < kstack_depth_to_print; i++) { + if (((long) stack & (THREAD_SIZE-1)) == 0) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + printk("%08lx ", *stack++); + } + + printk("\nCall Trace: "); + stack = sp; + i = 1; + module_start = VMALLOC_START; + module_end = VMALLOC_END; + while (((long) stack & (THREAD_SIZE-1)) != 0) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_stext) && + (addr <= (unsigned long) &_etext)) || + ((addr >= module_start) && (addr <= module_end))) { + if (i && ((i % 8) == 0)) + printk("\n "); + printk("[<%08lx>] ", addr); + i++; + } + } +} + +#if 0 +/* displays a short stack trace */ + +int show_stack() +{ + unsigned long *sp = (unsigned long *)rdusp(); + int i; + printk("Stack dump [0x%08lx]:\n", (unsigned long)sp); + for(i = 0; i < 16; i++) + printk("sp + %d: 0x%08lx\n", i*4, sp[i]); + return 0; +} +#endif + +void show_registers(struct pt_regs * regs) +{ + unsigned long usp = rdusp(); + + printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx\n", + regs->irp, regs->srp, regs->dccr, usp ); + printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", + regs->r0, regs->r1, regs->r2, regs->r3); + printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", + regs->r4, regs->r5, regs->r6, regs->r7); + printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", + regs->r8, regs->r9, regs->r10, regs->r11); + printk("r12: %08lx r13: %08lx oR10: %08lx\n", + regs->r12, regs->r13, regs->orig_r10); + printk("Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, (unsigned long)current); + + // TODO, fix in_kernel detection + +#if 0 + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (1) { + + printk("\nStack: "); + show_stack((unsigned long*)usp); + + printk("\nCode: "); + if(regs->irp < PAGE_OFFSET) + goto bad; + + for(i = 0; i < 20; i++) + { + unsigned char c; + if(__get_user(c, &((unsigned char*)regs->irp)[i])) { +bad: + printk(" Bad IP value."); + break; + } + printk("%02x ", c); + } + } + printk("\n"); +#endif +} + + + +void die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + if(user_mode(regs)) + return; + + printk("%s: %04lx\n", str, err & 0xffff); + + show_registers(regs); + show_stack(NULL); /* print backtrace for kernel stack on this CPU */ + + do_exit(SIGSEGV); +} + +void __init trap_init(void) +{ + + +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/lib/Makefile linux/arch/cris/lib/Makefile --- v2.4.1/linux/arch/cris/lib/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/Makefile Thu Feb 8 16:32:44 2001 @@ -0,0 +1,11 @@ +# +# Makefile for Etrax-specific library files.. +# + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o + +L_TARGET = lib.a +obj-y = checksum.o checksumcopy.o string.o usercopy.o memset.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/cris/lib/checksum.S linux/arch/cris/lib/checksum.S --- v2.4.1/linux/arch/cris/lib/checksum.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/checksum.S Thu Feb 8 16:32:44 2001 @@ -0,0 +1,113 @@ + ;; $Id: checksum.S,v 1.1 2000/07/10 16:25:21 bjornw Exp $ + ;; A fast checksum routine using movem + ;; Copyright (c) 1998 Bjorn Wesen/Axis Communications AB + + ;; csum_partial(const unsigned char * buff, int len, unsigned int sum) + + .globl _csum_partial +_csum_partial: + + ;; check for breakeven length between movem and normal word looping versions + + cmpu.w 80,r11 + bcs no_movem + nop + + ;; need to save the registers we use below in the movem loop + ;; this overhead is why we have a check above for breakeven length + + subq 9*4,sp + movem r8,[sp] + + ;; do a movem checksum + + ;; r10 - src + ;; r11 - length + ;; r12 - checksum + + subq 10*4,r11 ; update length for the first loop + +mloop: movem [r10+],r9 ; read 10 longwords + + ;; perform dword checksumming on the 10 longwords + + add.d r0,r12 + ax + add.d r1,r12 + ax + add.d r2,r12 + ax + add.d r3,r12 + ax + add.d r4,r12 + ax + add.d r5,r12 + ax + add.d r6,r12 + ax + add.d r7,r12 + ax + add.d r8,r12 + ax + add.d r9,r12 + + ;; fold the carry into the checksum, to avoid having to loop the carry + ;; back into the top + + ax + addq 0,r12 + ax ; do it again, since we might have generated a carry + addq 0,r12 + + subq 10*4,r11 + bge mloop + nop + + addq 10*4,r11 ; compensate for last loop underflowing length + + ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below + + moveq -1,r1 ; put 0xffff in r1, faster than move.d 0xffff,r1 + lsrq 16,r1 + + move.d r12,r0 + lsrq 16,r0 ; r0 = checksum >> 16 + and.d r1,r12 ; checksum = checksum & 0xffff + add.d r0,r12 ; checksum += r0 + move.d r12,r0 ; do the same again, maybe we got a carry last add + lsrq 16,r0 + and.d r1,r12 + add.d r0,r12 + + movem [sp+],r8 ; restore regs + +no_movem: + cmpq 2,r11 + blt no_words + nop + + ;; checksum the rest of the words + + subq 2,r11 + +wloop: subq 2,r11 + bge wloop + addu.w [r10+],r12 + + addq 2,r11 + +no_words: + ;; see if we have one odd byte more + cmpq 1,r11 + beq do_byte + nop + ret + move.d r12, r10 + +do_byte: + ;; copy and checksum the last byte + addu.b [r10],r12 + ret + move.d r12, r10 + + \ No newline at end of file diff -u --recursive --new-file v2.4.1/linux/arch/cris/lib/checksumcopy.S linux/arch/cris/lib/checksumcopy.S --- v2.4.1/linux/arch/cris/lib/checksumcopy.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/checksumcopy.S Thu Feb 8 16:32:44 2001 @@ -0,0 +1,120 @@ + ;; $Id: checksumcopy.S,v 1.2 2000/08/08 16:57:31 bjornw Exp $ + ;; A fast checksum+copy routine using movem + ;; Copyright (c) 1998, 2000 Axis Communications AB + ;; + ;; Authors: Bjorn Wesen + ;; + ;; csum_partial_copy_nocheck(const char *src, char *dst, + ;; int len, unsigned int sum) + + .globl _csum_partial_copy_nocheck +_csum_partial_copy_nocheck: + + ;; check for breakeven length between movem and normal word looping versions + + cmpu.w 80,r12 + bcs no_movem + nop + + ;; need to save the registers we use below in the movem loop + ;; this overhead is why we have a check above for breakeven length + + subq 9*4,sp + movem r8,[sp] + + ;; do a movem copy and checksum + + ;; r10 - src + ;; r11 - dst + ;; r12 - length + ;; r13 - checksum + + subq 10*4,r12 ; update length for the first loop + +mloop: movem [r10+],r9 ; read 10 longwords + movem r9,[r11+] ; write 10 longwords + + ;; perform dword checksumming on the 10 longwords + + add.d r0,r13 + ax + add.d r1,r13 + ax + add.d r2,r13 + ax + add.d r3,r13 + ax + add.d r4,r13 + ax + add.d r5,r13 + ax + add.d r6,r13 + ax + add.d r7,r13 + ax + add.d r8,r13 + ax + add.d r9,r13 + + ;; fold the carry into the checksum, to avoid having to loop the carry + ;; back into the top + + ax + addq 0,r13 + + subq 10*4,r12 + bge mloop + nop + + addq 10*4,r12 ; compensate for last loop underflowing length + + ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below + + moveq -1,r1 ; put 0xffff in r1, faster than move.d 0xffff,r1 + lsrq 16,r1 + + move.d r13,r0 + lsrq 16,r0 ; r0 = checksum >> 16 + and.d r1,r13 ; checksum = checksum & 0xffff + add.d r0,r13 ; checksum += r0 + move.d r13,r0 ; do the same again, maybe we got a carry last add + lsrq 16,r0 + and.d r1,r13 + add.d r0,r13 + + movem [sp+],r8 ; restore regs + +no_movem: + cmpq 2,r12 + blt no_words + nop + + ;; copy and checksum the rest of the words + + subq 2,r12 + +wloop: move.w [r10+],r9 + addu.w r9,r13 + subq 2,r12 + bge wloop + move.w r9,[r11+] + + addq 2,r12 + +no_words: + ;; see if we have one odd byte more + cmpq 1,r12 + beq do_byte + nop + ret + move.d r13, r10 + +do_byte: + ;; copy and checksum the last byte + move.b [r10],r9 + addu.b r9,r13 + move.b r9,[r11] + ret + move.d r13, r10 + + \ No newline at end of file diff -u --recursive --new-file v2.4.1/linux/arch/cris/lib/dmacopy.c linux/arch/cris/lib/dmacopy.c --- v2.4.1/linux/arch/cris/lib/dmacopy.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/dmacopy.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,43 @@ +/* $Id: dmacopy.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $ + * + * memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax + */ + +#include +#include + +#define D(x) + +void *dma_memcpy(void *pdst, + const void *psrc, + unsigned int pn) +{ + static etrax_dma_descr indma, outdma; + + D(printk("dma_memcpy %d bytes... ", pn)); + +#if 0 + *R_GEN_CONFIG = genconfig_shadow = + (genconfig_shadow & ~0x3c0000) | + IO_STATE(R_GEN_CONFIG, dma6, intdma7) | + IO_STATE(R_GEN_CONFIG, dma7, intdma6); +#endif + indma.sw_len = outdma.sw_len = pn; + indma.ctrl = d_eol | d_eop; + outdma.ctrl = d_eol; + indma.buf = psrc; + outdma.buf = pdst; + + *R_DMA_CH6_FIRST = &indma; + *R_DMA_CH7_FIRST = &outdma; + *R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, start); + *R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, start); + + while(*R_DMA_CH7_CMD == 1) /* wait for completion */ ; + + D(printk("done\n")); + +} + + + diff -u --recursive --new-file v2.4.1/linux/arch/cris/lib/memset.c linux/arch/cris/lib/memset.c --- v2.4.1/linux/arch/cris/lib/memset.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/memset.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,245 @@ +/*#************************************************************************#*/ +/*#-------------------------------------------------------------------------*/ +/*# */ +/*# FUNCTION NAME: memset() */ +/*# */ +/*# PARAMETERS: void* dst; Destination address. */ +/*# int c; Value of byte to write. */ +/*# int len; Number of bytes to write. */ +/*# */ +/*# RETURNS: dst. */ +/*# */ +/*# DESCRIPTION: Sets the memory dst of length len bytes to c, as standard. */ +/*# Framework taken from memcpy. This routine is */ +/*# very sensitive to compiler changes in register allocation. */ +/*# Should really be rewritten to avoid this problem. */ +/*# */ +/*#-------------------------------------------------------------------------*/ +/*# */ +/*# HISTORY */ +/*# */ +/*# DATE NAME CHANGES */ +/*# ---- ---- ------- */ +/*# 990713 HP Tired of watching this function (or */ +/*# really, the nonoptimized generic */ +/*# implementation) take up 90% of simulator */ +/*# output. Measurements needed. */ +/*# */ +/*#-------------------------------------------------------------------------*/ + +/* No, there's no macro saying 12*4, since it is "hard" to get it into + the asm in a good way. Thus better to expose the problem everywhere. + */ + +/* Assuming 1 cycle per dword written or read (ok, not really true), and + one per instruction, then 43+3*(n/48-1) <= 24+24*(n/48-1) + so n >= 45.7; n >= 0.9; we win on the first full 48-byte block to set. */ + +#define ZERO_BLOCK_SIZE (1*12*4) + +void *memset(void *pdst, + int c, + unsigned int plen) +{ + /* Ok. Now we want the parameters put in special registers. + Make sure the compiler is able to make something useful of this. */ + + register char *return_dst __asm__ ("r10") = pdst; + register int n __asm__ ("r12") = plen; + register int lc __asm__ ("r11") = c; + + /* Most apps use memset sanely. Only those memsetting about 3..4 + bytes or less get penalized compared to the generic implementation + - and that's not really sane use. */ + + /* Ugh. This is fragile at best. Check with newer GCC releases, if + they compile cascaded "x |= x << 8" sanely! */ + __asm__("movu.b %0,r13\n\tlslq 8,r13\n\tmove.b %0,r13\n\tmove.d r13,%0\n\tlslq 16,r13\n\tor.d r13,%0" + : "=r" (lc) : "0" (lc) : "r13"); + + { + register char *dst __asm__ ("r13") = pdst; + + /* This is NONPORTABLE, but since this whole routine is */ + /* grossly nonportable that doesn't matter. */ + + if (((unsigned long) pdst & 3) != 0 + /* Oops! n=0 must be a legal call, regardless of alignment. */ + && n >= 3) + { + if ((unsigned long)dst & 1) + { + *dst = (char) lc; + n--; + dst++; + } + + if ((unsigned long)dst & 2) + { + *(short *)dst = lc; + n -= 2; + dst += 2; + } + } + + /* Now the fun part. For the threshold value of this, check the equation + above. */ + /* Decide which copying method to use. */ + if (n >= ZERO_BLOCK_SIZE) + { + /* For large copies we use 'movem' */ + + /* It is not optimal to tell the compiler about clobbering any + registers; that will move the saving/restoring of those registers + to the function prologue/epilogue, and make non-movem sizes + suboptimal. + + This method is not foolproof; it assumes that the "asm reg" + declarations at the beginning of the function really are used + here (beware: they may be moved to temporary registers). + This way, we do not have to save/move the registers around into + temporaries; we can safely use them straight away. + + If you want to check that the allocation was right; then + check the equalities in the first comment. It should say + "r13=r13, r12=r12, r11=r11" */ + __asm__ volatile (" + ;; Check that the following is true (same register names on + ;; both sides of equal sign, as in r8=r8): + ;; %0=r13, %1=r12, %4=r11 + ;; + ;; Save the registers we'll clobber in the movem process + ;; on the stack. Don't mention them to gcc, it will only be + ;; upset. + subq 11*4,sp + movem r10,[sp] + + move.d r11,r0 + move.d r11,r1 + move.d r11,r2 + move.d r11,r3 + move.d r11,r4 + move.d r11,r5 + move.d r11,r6 + move.d r11,r7 + move.d r11,r8 + move.d r11,r9 + move.d r11,r10 + + ;; Now we've got this: + ;; r13 - dst + ;; r12 - n + + ;; Update n for the first loop + subq 12*4,r12 +0: + subq 12*4,r12 + bge 0b + movem r11,[r13+] + + addq 12*4,r12 ;; compensate for last loop underflowing n + + ;; Restore registers from stack + movem [sp+],r10" + + /* Outputs */ : "=r" (dst), "=r" (n) + /* Inputs */ : "0" (dst), "1" (n), "r" (lc)); + + } + + /* Either we directly starts copying, using dword copying + in a loop, or we copy as much as possible with 'movem' + and then the last block (<44 bytes) is copied here. + This will work since 'movem' will have updated src,dst,n. */ + + while ( n >= 16 ) + { + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + n -= 16; + } + + /* A switch() is definitely the fastest although it takes a LOT of code. + * Particularly if you inline code this. + */ + switch (n) + { + case 0: + break; + case 1: + *(char*)dst = (char) lc; + break; + case 2: + *(short*)dst = (short) lc; + break; + case 3: + *((short*)dst)++ = (short) lc; + *(char*)dst = (char) lc; + break; + case 4: + *((long*)dst)++ = lc; + break; + case 5: + *((long*)dst)++ = lc; + *(char*)dst = (char) lc; + break; + case 6: + *((long*)dst)++ = lc; + *(short*)dst = (short) lc; + break; + case 7: + *((long*)dst)++ = lc; + *((short*)dst)++ = (short) lc; + *(char*)dst = (char) lc; + break; + case 8: + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + break; + case 9: + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *(char*)dst = (char) lc; + break; + case 10: + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *(short*)dst = (short) lc; + break; + case 11: + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *((short*)dst)++ = (short) lc; + *(char*)dst = (char) lc; + break; + case 12: + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + break; + case 13: + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *(char*)dst = (char) lc; + break; + case 14: + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *(short*)dst = (short) lc; + break; + case 15: + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *((long*)dst)++ = lc; + *((short*)dst)++ = (short) lc; + *(char*)dst = (char) lc; + break; + } + } + + return return_dst; /* destination pointer. */ +} /* memset() */ diff -u --recursive --new-file v2.4.1/linux/arch/cris/lib/old_checksum.c linux/arch/cris/lib/old_checksum.c --- v2.4.1/linux/arch/cris/lib/old_checksum.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/old_checksum.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,127 @@ +/* $Id: old_checksum.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $ + * + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * IP/TCP/UDP checksumming routines + * + * Authors: Jorge Cwik, + * Arnt Gulbrandsen, + * Tom May, + * Lots of code moved from tcp.c and ip.c; see those files + * for more names. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the 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 + +#undef PROFILE_CHECKSUM + +#ifdef PROFILE_CHECKSUM +/* these are just for profiling the checksum code with an oscillioscope.. uh */ +#if 0 +#define BITOFF *((unsigned char *)0xb0000030) = 0xff +#define BITON *((unsigned char *)0xb0000030) = 0x0 +#endif +#include +#define CBITON LED_ACTIVE_SET(1) +#define CBITOFF LED_ACTIVE_SET(0) +#define BITOFF +#define BITON +#else +#define BITOFF +#define BITON +#define CBITOFF +#define CBITON +#endif + +/* + * computes a partial checksum, e.g. for TCP/UDP fragments + */ + +#include + +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) +{ + /* + * Experiments with ethernet and slip connections show that buff + * is aligned on either a 2-byte or 4-byte boundary. + */ + const unsigned char *endMarker = buff + len; + const unsigned char *marker = endMarker - (len % 16); +#if 0 + if((int)buff & 0x3) + printk("unaligned buff %p\n", buff); + __delay(900); /* extra delay of 90 us to test performance hit */ +#endif + BITON; + while (buff < marker) { + sum += *((unsigned short *)buff)++; + sum += *((unsigned short *)buff)++; + sum += *((unsigned short *)buff)++; + sum += *((unsigned short *)buff)++; + sum += *((unsigned short *)buff)++; + sum += *((unsigned short *)buff)++; + sum += *((unsigned short *)buff)++; + sum += *((unsigned short *)buff)++; + } + marker = endMarker - (len % 2); + while(buff < marker) { + sum += *((unsigned short *)buff)++; + } + if(endMarker - buff > 0) { + sum += *buff; /* add extra byte seperately */ + } + BITOFF; + return(sum); +} + +#if 0 + +/* + * copy while checksumming, otherwise like csum_partial + */ + +unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst, + int len, unsigned int sum) +{ + const unsigned char *endMarker; + const unsigned char *marker; + printk("csum_partial_copy len %d.\n", len); +#if 0 + if((int)src & 0x3) + printk("unaligned src %p\n", src); + if((int)dst & 0x3) + printk("unaligned dst %p\n", dst); + __delay(1800); /* extra delay of 90 us to test performance hit */ +#endif + endMarker = src + len; + marker = endMarker - (len % 16); + CBITON; + while(src < marker) { + sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++); + sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++); + sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++); + sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++); + sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++); + sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++); + sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++); + sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++); + } + marker = endMarker - (len % 2); + while(src < marker) { + sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++); + } + if(endMarker - src > 0) { + sum += (*dst = *src); /* add extra byte seperately */ + } + CBITOFF; + return(sum); +} + +#endif diff -u --recursive --new-file v2.4.1/linux/arch/cris/lib/string.c linux/arch/cris/lib/string.c --- v2.4.1/linux/arch/cris/lib/string.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/string.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,223 @@ +/*#************************************************************************#*/ +/*#-------------------------------------------------------------------------*/ +/*# */ +/*# FUNCTION NAME: memcpy() */ +/*# */ +/*# PARAMETERS: void* dst; Destination address. */ +/*# void* src; Source address. */ +/*# int len; Number of bytes to copy. */ +/*# */ +/*# RETURNS: dst. */ +/*# */ +/*# DESCRIPTION: Copies len bytes of memory from src to dst. No guarantees */ +/*# about copying of overlapping memory areas. This routine is */ +/*# very sensitive to compiler changes in register allocation. */ +/*# Should really be rewritten to avoid this problem. */ +/*# */ +/*#-------------------------------------------------------------------------*/ +/*# */ +/*# HISTORY */ +/*# */ +/*# DATE NAME CHANGES */ +/*# ---- ---- ------- */ +/*# 941007 Kenny R Creation */ +/*# 941011 Kenny R Lots of optimizations and inlining. */ +/*# 941129 Ulf A Adapted for use in libc. */ +/*# 950216 HP N==0 forgotten if non-aligned src/dst. */ +/*# Added some optimizations. */ +/*# 001025 HP Make src and dst char *. Align dst to */ +/*# dword, not just word-if-both-src-and-dst- */ +/*# are-misaligned. */ +/*# */ +/*#-------------------------------------------------------------------------*/ + +void *memcpy(void *pdst, + const void *psrc, + unsigned int pn) +{ + /* Ok. Now we want the parameters put in special registers. + Make sure the compiler is able to make something useful of this. + As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). + + If gcc was allright, it really would need no temporaries, and no + stack space to save stuff on. */ + + register void *return_dst __asm__ ("r10") = pdst; + register char *dst __asm__ ("r13") = pdst; + register const char *src __asm__ ("r11") = psrc; + register int n __asm__ ("r12") = pn; + + + /* When src is aligned but not dst, this makes a few extra needless + cycles. I believe it would take as many to check that the + re-alignment was unnecessary. */ + if (((unsigned long) dst & 3) != 0 + /* Don't align if we wouldn't copy more than a few bytes; so we + don't have to check further for overflows. */ + && n >= 3) + { + if ((unsigned long) dst & 1) + { + n--; + *(char*)dst = *(char*)src; + src++; + dst++; + } + + if ((unsigned long) dst & 2) + { + n -= 2; + *(short*)dst = *(short*)src; + src += 2; + dst += 2; + } + } + + /* Decide which copying method to use. */ + if (n >= 44*2) /* Break even between movem and + move16 is at 38.7*2, but modulo 44. */ + { + /* For large copies we use 'movem' */ + + /* It is not optimal to tell the compiler about clobbering any + registers; that will move the saving/restoring of those registers + to the function prologue/epilogue, and make non-movem sizes + suboptimal. + + This method is not foolproof; it assumes that the "asm reg" + declarations at the beginning of the function really are used + here (beware: they may be moved to temporary registers). + This way, we do not have to save/move the registers around into + temporaries; we can safely use them straight away. + + If you want to check that the allocation was right; then + check the equalities in the first comment. It should say + "r13=r13, r11=r11, r12=r12" */ + __asm__ volatile (" + ;; Check that the following is true (same register names on + ;; both sides of equal sign, as in r8=r8): + ;; %0=r13, %1=r11, %2=r12 + ;; + ;; Save the registers we'll use in the movem process + ;; on the stack. + subq 11*4,sp + movem r10,[sp] + + ;; Now we've got this: + ;; r11 - src + ;; r13 - dst + ;; r12 - n + + ;; Update n for the first loop + subq 44,r12 +0: + movem [r11+],r10 + subq 44,r12 + bge 0b + movem r10,[r13+] + + addq 44,r12 ;; compensate for last loop underflowing n + + ;; Restore registers from stack + movem [sp+],r10" + + /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n) + /* Inputs */ : "0" (dst), "1" (src), "2" (n)); + + } + + /* Either we directly starts copying, using dword copying + in a loop, or we copy as much as possible with 'movem' + and then the last block (<44 bytes) is copied here. + This will work since 'movem' will have updated src,dst,n. */ + + while ( n >= 16 ) + { + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + n -= 16; + } + + /* A switch() is definitely the fastest although it takes a LOT of code. + * Particularly if you inline code this. + */ + switch (n) + { + case 0: + break; + case 1: + *(char*)dst = *(char*)src; + break; + case 2: + *(short*)dst = *(short*)src; + break; + case 3: + *((short*)dst)++ = *((short*)src)++; + *(char*)dst = *(char*)src; + break; + case 4: + *((long*)dst)++ = *((long*)src)++; + break; + case 5: + *((long*)dst)++ = *((long*)src)++; + *(char*)dst = *(char*)src; + break; + case 6: + *((long*)dst)++ = *((long*)src)++; + *(short*)dst = *(short*)src; + break; + case 7: + *((long*)dst)++ = *((long*)src)++; + *((short*)dst)++ = *((short*)src)++; + *(char*)dst = *(char*)src; + break; + case 8: + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + break; + case 9: + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *(char*)dst = *(char*)src; + break; + case 10: + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *(short*)dst = *(short*)src; + break; + case 11: + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *((short*)dst)++ = *((short*)src)++; + *(char*)dst = *(char*)src; + break; + case 12: + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + break; + case 13: + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *(char*)dst = *(char*)src; + break; + case 14: + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *(short*)dst = *(short*)src; + break; + case 15: + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *((long*)dst)++ = *((long*)src)++; + *((short*)dst)++ = *((short*)src)++; + *(char*)dst = *(char*)src; + break; + } + + return return_dst; /* destination pointer. */ +} /* memcpy() */ diff -u --recursive --new-file v2.4.1/linux/arch/cris/lib/usercopy.c linux/arch/cris/lib/usercopy.c --- v2.4.1/linux/arch/cris/lib/usercopy.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/usercopy.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,501 @@ +/* + * User address space access functions. + * The non-inlined parts of asm-cris/uaccess.h are here. + * + * Copyright (C) 2000, Axis Communications AB. + * + * Written by Hans-Peter Nilsson. + * Pieces used from memcpy, originally by Kenny Ranerup long time ago. + */ + +#include + +/* Asm:s have been tweaked (within the domain of correctness) to give + satisfactory results for "gcc version 2.96 20000427 (experimental)". + + Check regularly... + + Note that the PC saved at a bus-fault is the address *after* the + faulting instruction, which means the branch-target for instructions in + delay-slots for taken branches. Note also that the postincrement in + the instruction is performed regardless of bus-fault; the register is + seen updated in fault handlers. + + Oh, and on the code formatting issue, to whomever feels like "fixing + it" to Conformity: I'm too "lazy", but why don't you go ahead and "fix" + string.c too. I just don't think too many people will hack this file + for the code format to be an issue. */ + + +/* Copy to userspace. This is based on the memcpy used for + kernel-to-kernel copying; see "string.c". */ + +unsigned long +__copy_user (void *pdst, const void *psrc, unsigned long pn) +{ + /* We want the parameters put in special registers. + Make sure the compiler is able to make something useful of this. + As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). + + FIXME: Comment for old gcc version. Check. + If gcc was allright, it really would need no temporaries, and no + stack space to save stuff on. */ + + register char *dst __asm__ ("r13") = pdst; + register const char *src __asm__ ("r11") = psrc; + register int n __asm__ ("r12") = pn; + register int retn __asm__ ("r10") = 0; + + + /* When src is aligned but not dst, this makes a few extra needless + cycles. I believe it would take as many to check that the + re-alignment was unnecessary. */ + if (((unsigned long) dst & 3) != 0 + /* Don't align if we wouldn't copy more than a few bytes; so we + don't have to check further for overflows. */ + && n >= 3) + { + if ((unsigned long) dst & 1) + { + __asm_copy_to_user_1 (dst, src, retn); + n--; + } + + if ((unsigned long) dst & 2) + { + __asm_copy_to_user_2 (dst, src, retn); + n -= 2; + } + } + + /* Decide which copying method to use. */ + if (n >= 44*2) /* Break even between movem and + move16 is at 38.7*2, but modulo 44. */ + { + /* For large copies we use 'movem'. */ + + /* It is not optimal to tell the compiler about clobbering any + registers; that will move the saving/restoring of those registers + to the function prologue/epilogue, and make non-movem sizes + suboptimal. + + This method is not foolproof; it assumes that the "asm reg" + declarations at the beginning of the function really are used + here (beware: they may be moved to temporary registers). + This way, we do not have to save/move the registers around into + temporaries; we can safely use them straight away. + + If you want to check that the allocation was right; then + check the equalities in the first comment. It should say + "r13=r13, r11=r11, r12=r12". */ + __asm__ volatile (" + ;; Check that the following is true (same register names on + ;; both sides of equal sign, as in r8=r8): + ;; %0=r13, %1=r11, %2=r12 %3=r10 + ;; + ;; Save the registers we'll use in the movem process + ;; on the stack. + subq 11*4,sp + movem r10,[sp] + + ;; Now we've got this: + ;; r11 - src + ;; r13 - dst + ;; r12 - n + + ;; Update n for the first loop + subq 44,r12 + +; Since the noted PC of a faulting instruction in a delay-slot of a taken +; branch, is that of the branch target, we actually point at the from-movem +; for this case. There is no ambiguity here; if there was a fault in that +; instruction (meaning a kernel oops), the faulted PC would be the address +; after *that* movem. + +0: + movem [r11+],r10 + subq 44,r12 + bge 0b + movem r10,[r13+] +1: + addq 44,r12 ;; compensate for last loop underflowing n + + ;; Restore registers from stack + movem [sp+],r10 +2: + .section .fixup,\"ax\" + +; To provide a correct count in r10 of bytes that failed to be copied, +; we jump back into the loop if the loop-branch was taken. There is no +; performance penalty for sany use; the program will segfault soon enough. + +3: + move.d [sp],r10 + addq 44,r10 + move.d r10,[sp] + jump 0b +4: + movem [sp+],r10 + addq 44,r10 + addq 44,r12 + jump 2b + + .previous + .section __ex_table,\"a\" + .dword 0b,3b + .dword 1b,4b + .previous" + + /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn) + /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn)); + + } + + /* Either we directly start copying, using dword copying in a loop, or + we copy as much as possible with 'movem' and then the last block (<44 + bytes) is copied here. This will work since 'movem' will have + updated SRC, DST and N. */ + + while (n >= 16) + { + __asm_copy_to_user_16 (dst, src, retn); + n -= 16; + } + + /* Having a separate by-four loops cuts down on cache footprint. + FIXME: Test with and without; increasing switch to be 0..15. */ + while (n >= 4) + { + __asm_copy_to_user_4 (dst, src, retn); + n -= 4; + } + + switch (n) + { + case 0: + break; + case 1: + __asm_copy_to_user_1 (dst, src, retn); + break; + case 2: + __asm_copy_to_user_2 (dst, src, retn); + break; + case 3: + __asm_copy_to_user_3 (dst, src, retn); + break; + } + + return retn; +} + +/* Copy from user to kernel, zeroing the bytes that were inaccessible in + userland. */ + +unsigned long +__copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) +{ + /* We want the parameters put in special registers. + Make sure the compiler is able to make something useful of this. + As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). + + FIXME: Comment for old gcc version. Check. + If gcc was allright, it really would need no temporaries, and no + stack space to save stuff on. */ + + register char *dst __asm__ ("r13") = pdst; + register const char *src __asm__ ("r11") = psrc; + register int n __asm__ ("r12") = pn; + register int retn __asm__ ("r10") = 0; + + /* When src is aligned but not dst, this makes a few extra needless + cycles. I believe it would take as many to check that the + re-alignment was unnecessary. */ + if (((unsigned long) dst & 3) != 0 + /* Don't align if we wouldn't copy more than a few bytes; so we + don't have to check further for overflows. */ + && n >= 3) + { + if ((unsigned long) dst & 1) + { + __asm_copy_from_user_1 (dst, src, retn); + n--; + } + + if ((unsigned long) dst & 2) + { + __asm_copy_from_user_2 (dst, src, retn); + n -= 2; + } + } + + /* Decide which copying method to use. */ + if (n >= 44*2) /* Break even between movem and + move16 is at 38.7*2, but modulo 44. */ + { + /* For large copies we use 'movem' */ + + /* It is not optimal to tell the compiler about clobbering any + registers; that will move the saving/restoring of those registers + to the function prologue/epilogue, and make non-movem sizes + suboptimal. + + This method is not foolproof; it assumes that the "asm reg" + declarations at the beginning of the function really are used + here (beware: they may be moved to temporary registers). + This way, we do not have to save/move the registers around into + temporaries; we can safely use them straight away. + + If you want to check that the allocation was right; then + check the equalities in the first comment. It should say + "r13=r13, r11=r11, r12=r12" */ + __asm__ volatile (" + ;; Check that the following is true (same register names on + ;; both sides of equal sign, as in r8=r8): + ;; %0=r13, %1=r11, %2=r12 %3=r10 + ;; + ;; Save the registers we'll use in the movem process + ;; on the stack. + subq 11*4,sp + movem r10,[sp] + + ;; Now we've got this: + ;; r11 - src + ;; r13 - dst + ;; r12 - n + + ;; Update n for the first loop + subq 44,r12 +0: + movem [r11+],r10 +1: + subq 44,r12 + bge 0b + movem r10,[r13+] + + addq 44,r12 ;; compensate for last loop underflowing n + + ;; Restore registers from stack + movem [sp+],r10 + + .section .fixup,\"ax\" + +; To provide a correct count in r10 of bytes that failed to be copied, +; we jump back into the loop if the loop-branch was taken. +; There is no performance penalty; the program will segfault soon +; enough. + +3: + move.d [sp],r10 + addq 44,r10 + move.d r10,[sp] + clear.d r0 + clear.d r1 + clear.d r2 + clear.d r3 + clear.d r4 + clear.d r5 + clear.d r6 + clear.d r7 + clear.d r8 + clear.d r9 + clear.d r10 + jump 1b + + .previous + .section __ex_table,\"a\" + .dword 1b,3b + .previous" + + /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn) + /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn)); + + } + + /* Either we directly start copying here, using dword copying in a loop, + or we copy as much as possible with 'movem' and then the last block + (<44 bytes) is copied here. This will work since 'movem' will have + updated src, dst and n. */ + + while (n >= 16) + { + __asm_copy_from_user_16 (dst, src, retn); + n -= 16; + } + + /* Having a separate by-four loops cuts down on cache footprint. + FIXME: Test with and without; increasing switch to be 0..15. */ + while (n >= 4) + { + __asm_copy_from_user_4 (dst, src, retn); + n -= 4; + } + + switch (n) + { + case 0: + break; + case 1: + __asm_copy_from_user_1 (dst, src, retn); + break; + case 2: + __asm_copy_from_user_2 (dst, src, retn); + break; + case 3: + __asm_copy_from_user_3 (dst, src, retn); + break; + } + + return retn; +} + +/* Zero userspace. */ + +unsigned long +__do_clear_user (void *pto, unsigned long pn) +{ + /* We want the parameters put in special registers. + Make sure the compiler is able to make something useful of this. + As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). + + FIXME: Comment for old gcc version. Check. + If gcc was allright, it really would need no temporaries, and no + stack space to save stuff on. */ + + register char *dst __asm__ ("r13") = pto; + register int n __asm__ ("r12") = pn; + register int retn __asm__ ("r10") = 0; + + + if (((unsigned long) dst & 3) != 0 + /* Don't align if we wouldn't copy more than a few bytes. */ + && n >= 3) + { + if ((unsigned long) dst & 1) + { + __asm_clear_1 (dst, retn); + n--; + } + + if ((unsigned long) dst & 2) + { + __asm_clear_2 (dst, retn); + n -= 2; + } + } + + /* Decide which copying method to use. + FIXME: This number is from the "ordinary" kernel memset. */ + if (n >= (1*48)) + { + /* For large clears we use 'movem' */ + + /* It is not optimal to tell the compiler about clobbering any + call-saved registers; that will move the saving/restoring of + those registers to the function prologue/epilogue, and make + non-movem sizes suboptimal. + + This method is not foolproof; it assumes that the "asm reg" + declarations at the beginning of the function really are used + here (beware: they may be moved to temporary registers). + This way, we do not have to save/move the registers around into + temporaries; we can safely use them straight away. + + If you want to check that the allocation was right; then + check the equalities in the first comment. It should say + something like "r13=r13, r11=r11, r12=r12". */ + __asm__ volatile (" + ;; Check that the following is true (same register names on + ;; both sides of equal sign, as in r8=r8): + ;; %0=r13, %1=r12 %2=r10 + ;; + ;; Save the registers we'll clobber in the movem process + ;; on the stack. Don't mention them to gcc, it will only be + ;; upset. + subq 11*4,sp + movem r10,[sp] + + clear.d r0 + clear.d r1 + clear.d r2 + clear.d r3 + clear.d r4 + clear.d r5 + clear.d r6 + clear.d r7 + clear.d r8 + clear.d r9 + clear.d r10 + clear.d r11 + + ;; Now we've got this: + ;; r13 - dst + ;; r12 - n + + ;; Update n for the first loop + subq 12*4,r12 +0: + subq 12*4,r12 + bge 0b + movem r11,[r13+] +1: + addq 12*4,r12 ;; compensate for last loop underflowing n + + ;; Restore registers from stack + movem [sp+],r10 +2: + .section .fixup,\"ax\" +3: + move.d [sp],r10 + addq 12*4,r10 + move.d r10,[sp] + clear.d r10 + jump 0b + +4: + movem [sp+],r10 + addq 12*4,r10 + addq 12*4,r12 + jump 2b + + .previous + .section __ex_table,\"a\" + .dword 0b,3b + .dword 1b,4b + .previous" + + /* Outputs */ : "=r" (dst), "=r" (n), "=r" (retn) + /* Inputs */ : "0" (dst), "1" (n), "2" (retn) + /* Clobber */ : "r11"); + } + + while (n >= 16) + { + __asm_clear_16 (dst, retn); + n -= 16; + } + + /* Having a separate by-four loops cuts down on cache footprint. + FIXME: Test with and without; increasing switch to be 0..15. */ + while (n >= 4) + { + __asm_clear_4 (dst, retn); + n -= 4; + } + + switch (n) + { + case 0: + break; + case 1: + __asm_clear_1 (dst, retn); + break; + case 2: + __asm_clear_2 (dst, retn); + break; + case 3: + __asm_clear_3 (dst, retn); + break; + } + + return retn; +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/mm/Makefile linux/arch/cris/mm/Makefile --- v2.4.1/linux/arch/cris/mm/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/mm/Makefile Thu Feb 8 16:32:44 2001 @@ -0,0 +1,13 @@ +# +# Makefile for the linux cris-specific parts of the memory manager. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := mm.o +obj-y := init.o fault.o tlb.o extable.o + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/cris/mm/extable.c linux/arch/cris/mm/extable.c --- v2.4.1/linux/arch/cris/mm/extable.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/mm/extable.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,55 @@ +/* + * linux/arch/cris/mm/extable.c + */ + +#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->fixup; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return 0; +} + +unsigned long +search_exception_table(unsigned long addr) +{ + unsigned long ret; + +#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.4.1/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c --- v2.4.1/linux/arch/cris/mm/fault.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/mm/fault.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,390 @@ +/* + * linux/arch/cris/mm/fault.c + * + * Copyright (C) 2000 Axis Communications AB + * + * Authors: Bjorn Wesen + * + * $Log: fault.c,v $ + * Revision 1.8 2000/11/22 14:45:31 bjornw + * * 2.4.0-test10 removed the set_pgdir instantaneous kernel global mapping + * into all processes. Instead we fill in the missing PTE entries on demand. + * + * Revision 1.7 2000/11/21 16:39:09 bjornw + * fixup switches frametype + * + * Revision 1.6 2000/11/17 16:54:08 bjornw + * More detailed siginfo reporting + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern void die_if_kernel(const char *,struct pt_regs *,long); + +asmlinkage void do_invalid_op (struct pt_regs *, unsigned long); +asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs, + int error_code); + +/* debug of low-level TLB reload */ +#define D(x) +/* debug of higher-level faults */ +#define DPG(x) + +/* fast TLB-fill fault handler */ + +void +handle_mmu_bus_fault(struct pt_regs *regs) +{ + int cause, select; + int index; + int page_id; + int miss, we, acc, inv; + struct mm_struct *mm = current->active_mm; + pmd_t *pmd; + pte_t pte; + int errcode = 0; + unsigned long address; + + cause = *R_MMU_CAUSE; + select = *R_TLB_SELECT; + + address = cause & PAGE_MASK; /* get faulting address */ + + page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); + miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); + we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); + acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); + inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); + index = IO_EXTRACT(R_TLB_SELECT, index, select); + + D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, " + "idx %d pid %d\n", + regs->irp, address, miss, inv, we, acc, index, page_id)); + + /* for a miss, we need to reload the TLB entry */ + + if(miss) { + + /* see if the pte exists at all */ + + pmd = (pmd_t *)pgd_offset(mm, address); + if(pmd_none(*pmd)) + goto dofault; + if(pmd_bad(*pmd)) { + printk("bad pgdir entry 0x%x at 0x%x\n", *pmd, pmd); + pmd_clear(pmd); + return; + } + pte = *pte_offset(pmd, address); + if(!pte_present(pte)) + goto dofault; + + D(printk(" found pte %x pg %x ", pte_val(pte), pte_page(pte))); + D( + { + if(pte_val(pte) & _PAGE_SILENT_WRITE) + printk("Silent-W "); + if(pte_val(pte) & _PAGE_KERNEL) + printk("Kernel "); + if(pte_val(pte) & _PAGE_SILENT_READ) + printk("Silent-R "); + if(pte_val(pte) & _PAGE_GLOBAL) + printk("Global "); + if(pte_val(pte) & _PAGE_PRESENT) + printk("Present "); + if(pte_val(pte) & _PAGE_ACCESSED) + printk("Accessed "); + if(pte_val(pte) & _PAGE_MODIFIED) + printk("Modified "); + if(pte_val(pte) & _PAGE_READ) + printk("Readable "); + if(pte_val(pte) & _PAGE_WRITE) + printk("Writeable "); + printk("\n"); + }); + + /* load up the chosen TLB entry + * this assumes the pte format is the same as the TLB_LO layout. + * + * the write to R_TLB_LO also writes the vpn and page_id fields from + * R_MMU_CAUSE, which we in this case obviously want to keep + */ + + *R_TLB_LO = pte_val(pte); + + return; + } + + errcode = 0x01 | (we << 1); + + dofault: + /* leave it to the MM system fault handler below */ + D(printk("do_page_fault %p errcode %d\n", address, errcode)); + do_page_fault(address, regs, errcode); +} + +/* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + * + * Notice that the address we're given is aligned to the page the fault + * occured in, since we only get the PFN in R_MMU_CAUSE not the complete + * address. + * + * error_code: + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + * + * If this routine detects a bad access, it returns 1, otherwise it + * returns 0. + */ + +asmlinkage void +do_page_fault(unsigned long address, struct pt_regs *regs, + int error_code) +{ + struct task_struct *tsk; + struct mm_struct *mm; + struct vm_area_struct * vma; + int writeaccess; + int fault; + unsigned long fixup; + siginfo_t info; + + tsk = current; + + /* + * We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + * + * NOTE! We MUST NOT take any locks for this case. We may + * be in an interrupt or a critical region, and should + * only copy the information from the master page table, + * nothing more. + * + * NOTE2: This is done so that, when updating the vmalloc + * mappings we don't have to walk all processes pgdirs and + * add the high mappings all at once. Instead we do it as they + * are used. + * + * TODO: On CRIS, we have a PTE Global bit which should be set in + * all the PTE's related to vmalloc in all processes - that means if + * we switch process and a vmalloc PTE is still in the TLB, it won't + * need to be reloaded. It's an optimization. + * + * Linux/CRIS's kernel is not page-mapped, so the comparision below + * should really be >= VMALLOC_START, however, kernel fixup errors + * will be handled more quickly by going through vmalloc_fault and then + * into bad_area_nosemaphore than falling through the find_vma user-mode + * tests. + */ + + if (address >= TASK_SIZE) + goto vmalloc_fault; + + mm = tsk->mm; + writeaccess = error_code & 2; + info.si_code = SEGV_MAPERR; + + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + + if (in_interrupt() || !mm) + goto no_context; + + down(&mm->mmap_sem); + vma = find_vma(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 (user_mode(regs)) { + /* + * accessing the stack below usp is always a bug. + * we get page-aligned addresses so we can only check + * if we're within a page from usp, but that might be + * enough to catch brutal errors at least. + */ + if (address + PAGE_SIZE < rdusp()) + 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: + info.si_code = SEGV_ACCERR; + + /* first do some preliminary protection checks */ + + if (writeaccess) { + 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. + */ + + switch (handle_mm_fault(mm, vma, address, writeaccess)) { + case 1: + tsk->min_flt++; + break; + case 2: + tsk->maj_flt++; + break; + case 0: + goto do_sigbus; + default: + goto out_of_memory; + } + + 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); + + bad_area_nosemaphore: + DPG(show_registers(regs)); + + /* User mode accesses just cause a SIGSEGV */ + + if (user_mode(regs)) { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* info.si_code has been set above */ + info.si_addr = (void *)address; + force_sig_info(SIGSEGV, &info, tsk); + return; + } + + no_context: + + /* Are we prepared to handle this kernel fault? + * + * (The kernel has valid exception-points in the source + * when it acesses user-memory. When it fails in one + * of those points, we find it in a table and do a jump + * to some fixup code that loads an appropriate error + * code) + */ + + if ((fixup = search_exception_table(regs->irp)) != 0) { + regs->irp = fixup; + regs->frametype = CRIS_FRAME_FIXUP; + D(printk("doing fixup to 0x%x\n", fixup)); + return; + } + +/* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if ((unsigned long) (address) < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel access"); + printk(" at virtual address %08lx\n",address); + + die_if_kernel("Oops", regs, error_code); + + 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. + */ + info.si_code = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + force_sig_info(SIGBUS, &info, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!user_mode(regs)) + goto no_context; + return; + +vmalloc_fault: + { + /* + * Synchronize this task's top level page-table + * with the 'reference' page table. + */ + int offset = pgd_index(address); + pgd_t *pgd, *pgd_k; + pmd_t *pmd, *pmd_k; + + pgd = tsk->active_mm->pgd + offset; + pgd_k = init_mm.pgd + offset; + + if (!pgd_present(*pgd)) { + if (!pgd_present(*pgd_k)) + goto bad_area_nosemaphore; + set_pgd(pgd, *pgd_k); + return; + } + + pmd = pmd_offset(pgd, address); + pmd_k = pmd_offset(pgd_k, address); + + if (pmd_present(*pmd) || !pmd_present(*pmd_k)) + goto bad_area_nosemaphore; + set_pmd(pmd, *pmd_k); + return; + } + +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c --- v2.4.1/linux/arch/cris/mm/init.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/mm/init.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,506 @@ +/* + * linux/arch/cris/mm/init.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 2000 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * $Log: init.c,v $ + * Revision 1.15 2001/01/10 21:12:10 bjornw + * loops_per_sec -> loops_per_jiffy + * + * Revision 1.14 2000/11/22 16:23:20 bjornw + * Initialize totalhigh counters to 0 to make /proc/meminfo look nice. + * + * Revision 1.13 2000/11/21 16:37:51 bjornw + * Temporarily disable initmem freeing + * + * Revision 1.12 2000/11/21 13:55:07 bjornw + * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type + * + * Revision 1.11 2000/10/06 12:38:22 bjornw + * Cast empty_bad_page correctly (should really be of * type from the start.. + * + * Revision 1.10 2000/10/04 16:53:57 bjornw + * Fix memory-map due to LX features + * + * Revision 1.9 2000/09/13 15:47:49 bjornw + * Wrong count in reserved-pages loop + * + * Revision 1.8 2000/09/13 14:35:10 bjornw + * 2.4.0-test8 added a new arg to free_area_init_node + * + * Revision 1.7 2000/08/17 15:35:55 bjornw + * 2.4.0-test6 removed MAP_NR and inserted virt_to_page + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static unsigned long totalram_pages; + +struct pgtable_cache_struct quicklists; /* see asm/pgalloc.h */ + +const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; + +extern void die_if_kernel(char *,struct pt_regs *,long); +extern void show_net_buffers(void); +extern void tlb_init(void); + +/* + * empty_bad_page is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving a inode + * unused etc.. + * + * the main point is that when a page table error occurs, we want to get + * out of the kernel safely before killing the process, so we need something + * to feed the MMU with when the fault occurs even if we don't have any + * real PTE's or page tables. + * + * empty_bad_page_table is the accompanying page-table: it is initialized + * to point to empty_bad_page writable-shared entries. + * + * empty_zero_page is a special page that is used for zero-initialized + * data and COW. + */ + +unsigned long empty_bad_page_table; +unsigned long empty_bad_page; +unsigned long empty_zero_page; + +pte_t * __bad_pagetable(void) +{ + /* somehow it is enough to just clear it and not fill it with + * bad page PTE's... + */ + memset((void *)empty_bad_page_table, 0, PAGE_SIZE); + + return (pte_t *) empty_bad_page_table; +} + +pte_t __bad_page(void) +{ + + /* clear the empty_bad_page page. this should perhaps be + * a more simple inlined loop like it is on the other + * architectures. + */ + + memset((void *)empty_bad_page, 0, PAGE_SIZE); + + return pte_mkdirty(__mk_pte((void *)empty_bad_page, PAGE_SHARED)); +} + +static pte_t * get_bad_pte_table(void) +{ + pte_t *empty_bad_pte_table = (pte_t *)empty_bad_page_table; + pte_t v; + int i; + + v = __bad_page(); + + for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++) + empty_bad_pte_table[i] = v; + + return empty_bad_pte_table; +} + +void __handle_bad_pmd(pmd_t *pmd) +{ + pmd_ERROR(*pmd); + pmd_set(pmd, get_bad_pte_table()); +} + +void __handle_bad_pmd_kernel(pmd_t *pmd) +{ + pmd_ERROR(*pmd); + pmd_set_kernel(pmd, get_bad_pte_table()); +} + +pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + clear_page(pte); + pmd_set_kernel(pmd, pte); + return pte + offset; + } + pmd_set_kernel(pmd, get_bad_pte_table()); + return NULL; + } + free_page((unsigned long)pte); + if (pmd_bad(*pmd)) { + __handle_bad_pmd_kernel(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) __get_free_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + clear_page(pte); + pmd_set(pmd, pte); + return pte + offset; + } + pmd_set(pmd, get_bad_pte_table()); + return NULL; + } + free_page((unsigned long)pte); + if (pmd_bad(*pmd)) { + __handle_bad_pmd(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +#ifndef CONFIG_NO_PGT_CACHE +struct pgtable_cache_struct quicklists; + +/* trim the page-table cache if necessary */ + +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; +} +#else +int do_check_pgt_cache(int low, int high) +{ + return 0; +} +#endif + +void show_mem(void) +{ + int i,free = 0,total = 0,cached = 0, reserved = 0, nonshared = 0; + int shared = 0; + + printk("\nMem-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 if (page_count(mem_map+i) == 1) + nonshared++; + else + shared += page_count(mem_map+i) - 1; + } + printk("%d pages of RAM\n",total); + printk("%d free pages\n",free); + printk("%d reserved pages\n",reserved); + printk("%d pages nonshared\n",nonshared); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); + printk("%ld pages in page table cache\n",pgtable_cache_size); + show_buffers(); +} + +/* + * The kernel is already mapped with a kernel segment at kseg_c so + * we don't need to map it with a page table. However head.S also + * temporarily mapped it at kseg_4 so we should set up the ksegs again, + * clear the TLB and do some other paging setup stuff. + */ + +void __init +paging_init(void) +{ + int i; + unsigned long zones_size[MAX_NR_ZONES]; + + printk("Setting up paging and the MMU.\n"); + + /* clear out the init_mm.pgd that will contain the kernel's mappings */ + + for(i = 0; i < PTRS_PER_PGD; i++) + swapper_pg_dir[i] = __pgd(0); + + /* initialise the TLB (tlb.c) */ + + tlb_init(); + + /* see README.mm for details on the KSEG setup */ + +#ifdef CONFIG_CRIS_LOW_MAP + + /* Etrax-100 LX version 1 has a bug so that we cannot map anything + * across the 0x80000000 boundary, so we need to shrink the user-virtual + * area to 0x50000000 instead of 0xb0000000 and map things slightly + * different. The unused areas are marked as paged so that we can catch + * freak kernel accesses there. + * + * The Juliette chip is mapped at 0xa so we pass that segment straight + * through. We cannot vremap it because the vmalloc area is below 0x8 + * and Juliette needs an uncached area above 0x8. + */ + + *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, page ) | + IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ + IO_STATE(R_MMU_KSEG, seg_d, page ) | + IO_STATE(R_MMU_KSEG, seg_c, page ) | + IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ + IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* Juliette etc. */ + IO_STATE(R_MMU_KSEG, seg_9, page ) | + IO_STATE(R_MMU_KSEG, seg_8, page ) | + IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ + IO_STATE(R_MMU_KSEG, seg_6, seg ) | /* kernel DRAM area */ + IO_STATE(R_MMU_KSEG, seg_5, seg ) | /* cached flash */ + IO_STATE(R_MMU_KSEG, seg_4, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_3, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_2, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_1, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */ + + *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | + IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | + IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) | + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); + + *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) | + IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); +#else + /* This code is for the hopefully corrected Etrax-100 LX version 2... */ + + *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ + IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ + IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ + IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ + IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ + IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_9, page ) | + IO_STATE(R_MMU_KSEG, seg_8, page ) | + IO_STATE(R_MMU_KSEG, seg_7, page ) | + IO_STATE(R_MMU_KSEG, seg_6, page ) | + IO_STATE(R_MMU_KSEG, seg_5, page ) | + IO_STATE(R_MMU_KSEG, seg_4, page ) | + IO_STATE(R_MMU_KSEG, seg_3, page ) | + IO_STATE(R_MMU_KSEG, seg_2, page ) | + IO_STATE(R_MMU_KSEG, seg_1, page ) | + IO_STATE(R_MMU_KSEG, seg_0, page ) ); + + *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | + IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | + IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | + IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); + + *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); +#endif + + *R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) ); + + /* The MMU has been enabled ever since head.S but just to make + * it totally obvious we do it here as well. + */ + + *R_MMU_CTRL = ( IO_STATE(R_MMU_CTRL, inv_excp, enable ) | + IO_STATE(R_MMU_CTRL, acc_excp, enable ) | + IO_STATE(R_MMU_CTRL, we_excp, enable ) ); + + *R_MMU_ENABLE = IO_STATE(R_MMU_ENABLE, mmu_enable, enable); + + /* + * initialize the bad page table and bad page to point + * to a couple of allocated pages + */ + + empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + /* All pages are DMA'able in Etrax, so put all in the DMA'able zone */ + + zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT; + + for (i = 1; i < MAX_NR_ZONES; i++) + zones_size[i] = 0; + + /* Use free_area_init_node instead of free_area_init, because the former + * is designed for systems where the DRAM starts at an address substantially + * higher than 0, like us (we start at PAGE_OFFSET). This saves space in the + * mem_map page array. + */ + + free_area_init_node(0, 0, 0, zones_size, PAGE_OFFSET, 0); +} + +extern unsigned long loops_per_jiffy; /* init/main.c */ +unsigned long loops_per_usec; + +extern char _stext, _edata, _etext; +extern char __init_begin, __init_end; + +void __init +mem_init(void) +{ + int codesize, reservedpages, datasize, initsize; + unsigned long tmp; + + if(!mem_map) + BUG(); + + /* max/min_low_pfn was set by setup.c + * now we just copy it to some other necessary places... + * + * high_memory was also set in setup.c + */ + + max_mapnr = num_physpages = max_low_pfn - min_low_pfn; + + /* this will put all memory onto the freelists */ + totalram_pages = free_all_bootmem(); + + reservedpages = 0; + for (tmp = 0; tmp < max_mapnr; tmp++) { + /* + * Only count reserved RAM pages + */ + if (PageReserved(mem_map + tmp)) + reservedpages++; + } + + codesize = (unsigned long) &_etext - (unsigned long) &_stext; + datasize = (unsigned long) &_edata - (unsigned long) &_etext; + initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, " + "%dk init)\n" , + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + max_mapnr << (PAGE_SHIFT-10), + codesize >> 10, + reservedpages << (PAGE_SHIFT-10), + datasize >> 10, + initsize >> 10 + ); + + /* HACK alert - calculate a loops_per_usec for asm/delay.h here + * since this is called just after calibrate_delay in init/main.c + * but before places which use udelay. cannot be in time.c since + * that is called _before_ calibrate_delay + */ + + loops_per_usec = (loops_per_jiffy * HZ) / 1000000; + + return; +} + +/* free the pages occupied by initialization code */ + +void free_initmem(void) +{ +#if 0 + /* currently this is a bad idea since the cramfs image is catted onto + * the vmlinux image, and the end of that image is not page-padded so + * part of the cramfs image will be freed here + */ + unsigned long addr; + + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + set_page_count(virt_to_page(addr), 1); + free_page(addr); + totalram_pages++; + } + printk ("Freeing unused kernel memory: %dk freed\n", + (&__init_end - &__init_begin) >> 10); +#endif +} + +void si_meminfo(struct sysinfo *val) +{ + int i; + + i = max_mapnr; + val->totalram = 0; + val->sharedram = 0; + val->freeram = nr_free_pages(); + val->bufferram = atomic_read(&buffermem_pages); + 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->mem_unit = PAGE_SIZE; + val->totalhigh = 0; + val->freehigh = 0; +} diff -u --recursive --new-file v2.4.1/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c --- v2.4.1/linux/arch/cris/mm/tlb.c Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/mm/tlb.c Thu Feb 8 16:32:44 2001 @@ -0,0 +1,301 @@ +/* + * linux/arch/cris/mm/tlb.c + * + * Copyright (C) 2000 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define D(x) + +/* CRIS in Etrax100LX TLB */ + +#define NUM_TLB_ENTRIES 64 +#define NUM_PAGEID 64 +#define INVALID_PAGEID 63 +#define NO_CONTEXT -1 + +/* The TLB can host up to 64 different mm contexts at the same time. + * The running context is R_MMU_CONTEXT, and each TLB entry contains a + * page_id that has to match to give a hit. In page_id_map, we keep track + * of which mm's we have assigned which page_id's, so that we know when + * to invalidate TLB entries. + * + * The last page_id is never running - it is used as an invalid page_id + * so we can make TLB entries that will never match. + */ + +struct mm_struct *page_id_map[NUM_PAGEID]; + +static int map_replace_ptr = 1; /* which page_id_map entry to replace next */ + +/* invalidate all TLB entries */ + +void +flush_tlb_all() +{ + int i; + + /* the vpn of i & 0xf is so we dont write similar TLB entries + * in the same 4-way entry group. details.. + */ + + for(i = 0; i < NUM_TLB_ENTRIES; i++) { + *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); + + *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | + IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); + + *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | + IO_STATE(R_TLB_LO, valid, no ) | + IO_STATE(R_TLB_LO, kernel,no ) | + IO_STATE(R_TLB_LO, we, no ) | + IO_FIELD(R_TLB_LO, pfn, 0 ) ); + } + D(printk("tlb: flushed all\n")); +} + +/* invalidate the selected mm context only */ + +void +flush_tlb_mm(struct mm_struct *mm) +{ + int i; + int page_id = mm->context; + + D(printk("tlb: flush mm context %d (%p)\n", page_id, mm)); + + if(page_id == NO_CONTEXT) + return; + + /* mark the TLB entries that match the page_id as invalid. + * here we could also check the _PAGE_GLOBAL bit and NOT flush + * global pages. is it worth the extra I/O ? + */ + + for(i = 0; i < NUM_TLB_ENTRIES; i++) { + *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); + if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) { + *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | + IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); + + *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | + IO_STATE(R_TLB_LO, valid, no ) | + IO_STATE(R_TLB_LO, kernel,no ) | + IO_STATE(R_TLB_LO, we, no ) | + IO_FIELD(R_TLB_LO, pfn, 0 ) ); + } + } +} + +/* invalidate a single page */ + +void +flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + struct mm_struct *mm = vma->vm_mm; + int page_id = mm->context; + int i; + + D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm)); + + if(page_id == NO_CONTEXT) + return; + + addr &= PAGE_MASK; /* perhaps not necessary */ + + /* invalidate those TLB entries that match both the mm context + * and the virtual address requested + */ + + for(i = 0; i < NUM_TLB_ENTRIES; i++) { + unsigned long tlb_hi; + *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); + tlb_hi = *R_TLB_HI; + if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id && + (tlb_hi & PAGE_MASK) == addr) { + *R_TLB_HI = IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | + addr; /* same addr as before works. */ + + *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | + IO_STATE(R_TLB_LO, valid, no ) | + IO_STATE(R_TLB_LO, kernel,no ) | + IO_STATE(R_TLB_LO, we, no ) | + IO_FIELD(R_TLB_LO, pfn, 0 ) ); + } + } +} + +/* invalidate a page range */ + +void +flush_tlb_range(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + int page_id = mm->context; + int i; + + D(printk("tlb: flush range %p<->%p in context %d (%p)\n", + start, end, page_id, mm)); + + if(page_id == NO_CONTEXT) + return; + + start &= PAGE_MASK; /* probably not necessary */ + end &= PAGE_MASK; /* dito */ + + /* invalidate those TLB entries that match both the mm context + * and the virtual address range + */ + + for(i = 0; i < NUM_TLB_ENTRIES; i++) { + unsigned long tlb_hi, vpn; + *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); + tlb_hi = *R_TLB_HI; + vpn = tlb_hi & PAGE_MASK; + if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id && + vpn >= start && vpn < end) { + *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | + IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); + + *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | + IO_STATE(R_TLB_LO, valid, no ) | + IO_STATE(R_TLB_LO, kernel,no ) | + IO_STATE(R_TLB_LO, we, no ) | + IO_FIELD(R_TLB_LO, pfn, 0 ) ); + } + } +} + +/* + * Initialize the context related info for a new mm_struct + * instance. + */ + +int +init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + mm->context = NO_CONTEXT; + return 0; +} + +/* the following functions are similar to those used in the PPC port */ + +static inline void +alloc_context(struct mm_struct *mm) +{ + struct mm_struct *old_mm; + + D(printk("tlb: alloc context %d (%p)\n", map_replace_ptr, mm)); + + /* did we replace an mm ? */ + + old_mm = page_id_map[map_replace_ptr]; + + if(old_mm) { + /* throw out any TLB entries belonging to the mm we replace + * in the map + */ + flush_tlb_mm(old_mm); + + old_mm->context = NO_CONTEXT; + } + + /* insert it into the page_id_map */ + + mm->context = map_replace_ptr; + page_id_map[map_replace_ptr] = mm; + + map_replace_ptr++; + + if(map_replace_ptr == INVALID_PAGEID) + map_replace_ptr = 0; /* wrap around */ + +} + +/* + * if needed, get a new MMU context for the mm. otherwise nothing is done. + */ + +void +get_mmu_context(struct mm_struct *mm) +{ + if(mm->context == NO_CONTEXT) + alloc_context(mm); +} + +/* called in schedule() just before actually doing the switch_to */ + +void +switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk, int cpu) +{ + /* make sure we have a context */ + + get_mmu_context(next); + + /* switch context in the MMU */ + + D(printk("switching mmu_context to %d (%p)\n", next->context, next)); + + *R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context); +} + + +/* called by __exit_mm to destroy the used MMU context if any before + * destroying the mm itself. this is only called when the last user of the mm + * drops it. + * + * the only thing we really need to do here is mark the used PID slot + * as empty. + */ + +void +destroy_context(struct mm_struct *mm) +{ + if(mm->context != NO_CONTEXT) { + D(printk("destroy_context %d (%p)\n", mm->context, mm)); + flush_tlb_mm(mm); /* TODO this might be redundant ? */ + page_id_map[mm->context] = NULL; + /* mm->context = NO_CONTEXT; redundant.. mm will be freed */ + } +} + +/* called once during VM initialization, from init.c */ + +void __init +tlb_init(void) +{ + int i; + + /* clear the page_id map */ + + for(i = 0; i < 64; i++) + page_id_map[i] = NULL; + + /* invalidate the entire TLB */ + + flush_tlb_all(); + + /* the init_mm has context 0 from the boot */ + + page_id_map[0] = &init_mm; +} diff -u --recursive --new-file v2.4.1/linux/arch/i386/boot/compressed/misc.c linux/arch/i386/boot/compressed/misc.c --- v2.4.1/linux/arch/i386/boot/compressed/misc.c Mon Jul 31 10:48:17 2000 +++ linux/arch/i386/boot/compressed/misc.c Tue Feb 13 13:15:04 2001 @@ -10,6 +10,7 @@ */ #include +#include #include /* * gzip declarations diff -u --recursive --new-file v2.4.1/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.1/linux/arch/i386/defconfig Sat Feb 3 19:51:22 2001 +++ linux/arch/i386/defconfig Mon Feb 19 17:10:28 2001 @@ -162,6 +162,11 @@ # CONFIG_BRIDGE is not set # +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# # Telephony Support # # CONFIG_PHONE is not set @@ -628,6 +633,8 @@ CONFIG_SOUND_ES1371=y # CONFIG_SOUND_ESSSOLO1 is not set # CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_ICH is not set # CONFIG_SOUND_SONICVIBES is not set # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.4.1/linux/arch/i386/kernel/apm.c Wed Dec 6 21:00:12 2000 +++ linux/arch/i386/kernel/apm.c Fri Feb 9 11:29:44 2001 @@ -176,7 +176,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c --- v2.4.1/linux/arch/i386/kernel/dmi_scan.c Fri Dec 29 14:07:20 2000 +++ linux/arch/i386/kernel/dmi_scan.c Tue Feb 13 14:13:43 2001 @@ -12,6 +12,8 @@ u16 handle; }; +#define dmi_printk(x) + static char * __init dmi_string(struct dmi_header *dm, u8 s) { u8 *bp=(u8 *)dm; @@ -73,13 +75,13 @@ u16 len=buf[7]<<8|buf[6]; u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]; - printk(KERN_INFO "DMI %d.%d present.\n", - buf[14]>>4, buf[14]&0x0F); - printk(KERN_INFO "%d structures occupying %d bytes.\n", + dmi_printk((KERN_INFO "DMI %d.%d present.\n", + buf[14]>>4, buf[14]&0x0F)); + dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n", buf[13]<<8|buf[12], - buf[7]<<8|buf[6]); - printk(KERN_INFO "DMI table at 0x%08X.\n", - buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]); + buf[7]<<8|buf[6])); + dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", + buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8])); if(dmi_table(base,len, num, decode)==0) return 0; } @@ -106,11 +108,11 @@ if(*p && *p!=' ') { - printk("BIOS Vendor: %s\n", p); - printk("BIOS Version: %s\n", - dmi_string(dm, data[5])); - printk("BIOS Release: %s\n", - dmi_string(dm, data[8])); + dmi_printk(("BIOS Vendor: %s\n", p)); + dmi_printk(("BIOS Version: %s\n", + dmi_string(dm, data[5]))); + dmi_printk(("BIOS Release: %s\n", + dmi_string(dm, data[8]))); } /* @@ -144,13 +146,13 @@ if(*p && *p!=' ') { - printk("System Vendor: %s.\n",p); - printk("Product Name: %s.\n", - dmi_string(dm, data[5])); - printk("Version %s.\n", - dmi_string(dm, data[6])); - printk("Serial Number %s.\n", - dmi_string(dm, data[7])); + dmi_printk(("System Vendor: %s.\n",p)); + dmi_printk(("Product Name: %s.\n", + dmi_string(dm, data[5]))); + dmi_printk(("Version %s.\n", + dmi_string(dm, data[6]))); + dmi_printk(("Serial Number %s.\n", + dmi_string(dm, data[7]))); } break; case 2: @@ -158,17 +160,17 @@ if(*p && *p!=' ') { - printk("Board Vendor: %s.\n",p); - printk("Board Name: %s.\n", - dmi_string(dm, data[5])); - printk("Board Version: %s.\n", - dmi_string(dm, data[6])); + dmi_printk(("Board Vendor: %s.\n",p)); + dmi_printk(("Board Name: %s.\n", + dmi_string(dm, data[5]))); + dmi_printk(("Board Version: %s.\n", + dmi_string(dm, data[6]))); } break; case 3: p=dmi_string(dm,data[8]); if(*p && *p!=' ') - printk("Asset Tag: %s.\n", p); + dmi_printk(("Asset Tag: %s.\n", p)); break; } } diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S --- v2.4.1/linux/arch/i386/kernel/head.S Tue Nov 28 22:43:39 2000 +++ linux/arch/i386/kernel/head.S Fri Feb 16 15:53:08 2001 @@ -34,7 +34,7 @@ #define X86_HARD_MATH CPU_PARAMS+6 #define X86_CPUID CPU_PARAMS+8 #define X86_CAPABILITY CPU_PARAMS+12 -#define X86_VENDOR_ID CPU_PARAMS+16 +#define X86_VENDOR_ID CPU_PARAMS+28 /* * swapper_pg_dir is the main page directory, address 0x00101000 diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.4.1/linux/arch/i386/kernel/i386_ksyms.c Wed Dec 6 21:00:12 2000 +++ linux/arch/i386/kernel/i386_ksyms.c Tue Feb 13 13:15:04 2001 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/i387.c linux/arch/i386/kernel/i387.c --- v2.4.1/linux/arch/i386/kernel/i387.c Sat Feb 3 19:51:22 2001 +++ linux/arch/i386/kernel/i387.c Sat Feb 3 12:09:34 2001 @@ -216,7 +216,7 @@ void set_fpu_mxcsr( struct task_struct *tsk, unsigned short mxcsr ) { if ( cpu_has_xmm ) { - tsk->thread.i387.fxsave.mxcsr = mxcsr; + tsk->thread.i387.fxsave.mxcsr = (mxcsr & 0xffbf); } } @@ -354,6 +354,8 @@ if ( __copy_from_user( &tsk->thread.i387.fxsave, &buf->_fxsr_env[0], sizeof(struct i387_fxsave_struct) ) ) return 1; + /* mxcsr bit 6 and 31-16 must be zero for security reasons */ + tsk->thread.i387.fxsave.mxcsr &= 0xffbf; return convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf ); } diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/i8259.c linux/arch/i386/kernel/i8259.c --- v2.4.1/linux/arch/i386/kernel/i8259.c Sat Nov 18 20:54:39 2000 +++ linux/arch/i386/kernel/i8259.c Fri Feb 9 11:29:44 2001 @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.4.1/linux/arch/i386/kernel/io_apic.c Sat Feb 3 19:51:22 2001 +++ linux/arch/i386/kernel/io_apic.c Fri Feb 9 11:28:31 2001 @@ -1509,15 +1509,16 @@ * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ. * Linux doesn't really care, as it's not actually used * for any interrupt handling anyway. - * - IRQ13 is the FPU error IRQ, and may be connected - * directly from the FPU to the old PIC. Linux doesn't - * really care, because Linux doesn't want to use IRQ13 - * anyway (exception 16 is the proper FPU error signal) + * - There used to be IRQ13 here as well, but all + * MPS-compliant must not use it for FPU coupling and we + * want to use exception 16 anyway. And there are + * systems who connect it to an I/O APIC for other uses. + * Thus we don't mark it special any longer. * * Additionally, something is definitely wrong with irq9 * on PIIX4 boards. */ -#define PIC_IRQS ((1<<2)|(1<<13)) +#define PIC_IRQS (1<<2) void __init setup_IO_APIC(void) { diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.4.1/linux/arch/i386/kernel/irq.c Sun Dec 3 17:48:19 2000 +++ linux/arch/i386/kernel/irq.c Fri Feb 9 11:29:44 2001 @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -312,6 +312,7 @@ /* Uhhuh.. Somebody else got it. Wait.. */ do { do { + rep_nop(); } while (test_bit(0,&global_irq_lock)); } while (test_and_set_bit(0,&global_irq_lock)); } diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/microcode.c linux/arch/i386/kernel/microcode.c --- v2.4.1/linux/arch/i386/kernel/microcode.c Mon Dec 11 13:42:08 2000 +++ linux/arch/i386/kernel/microcode.c Fri Feb 9 11:29:44 2001 @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.4.1/linux/arch/i386/kernel/mtrr.c Tue Nov 28 22:34:01 2000 +++ linux/arch/i386/kernel/mtrr.c Fri Feb 9 11:29:44 2001 @@ -241,7 +241,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c --- v2.4.1/linux/arch/i386/kernel/pci-irq.c Sat Feb 3 19:51:22 2001 +++ linux/arch/i386/kernel/pci-irq.c Fri Feb 9 11:29:44 2001 @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/pci-pc.c linux/arch/i386/kernel/pci-pc.c --- v2.4.1/linux/arch/i386/kernel/pci-pc.c Thu Jun 22 07:17:16 2000 +++ linux/arch/i386/kernel/pci-pc.c Thu Feb 8 11:36:58 2001 @@ -843,30 +843,40 @@ pcibios_last_bus = -1; } +/* + * ServerWorks host bridges -- Find and scan all secondary buses. + * Register 0x44 contains first, 0x45 last bus number routed there. + */ static void __init pci_fixup_serverworks(struct pci_dev *d) { - /* - * ServerWorks host bridges -- Find and scan all secondary buses. - * Register 0x44 contains first, 0x45 last bus number routed there. - */ - u8 busno; - pci_read_config_byte(d, 0x44, &busno); - printk("PCI: ServerWorks host bridge: secondary bus %02x\n", busno); - pci_scan_bus(busno, pci_root_ops, NULL); - pcibios_last_bus = -1; + u8 busno1, busno2; + + pci_read_config_byte(d, 0x44, &busno1); + pci_read_config_byte(d, 0x45, &busno2); + if (busno2 < busno1) + busno2 = busno1; + if (busno2 > pcibios_last_bus) { + pcibios_last_bus = busno2; + printk("PCI: ServerWorks host bridge: last bus %02x\n", pcibios_last_bus); + } } +/* + * Compaq host bridges -- Find and scan all secondary buses. + * This time registers 0xc8 and 0xc9. + */ static void __init pci_fixup_compaq(struct pci_dev *d) { - /* - * Compaq host bridges -- Find and scan all secondary buses. - * This time registers 0xc8 and 0xc9. - */ - u8 busno; - pci_read_config_byte(d, 0xc8, &busno); - printk("PCI: Compaq host bridge: secondary bus %02x\n", busno); - pci_scan_bus(busno, pci_root_ops, NULL); - pcibios_last_bus = -1; + u8 busno1, busno2; + + pci_read_config_byte(d, 0xc8, &busno1); + pci_read_config_byte(d, 0xc9, &busno2); + if (busno2 < busno1) + busno2 = busno1; + if (busno2 > pcibios_last_bus) { + pcibios_last_bus = busno2; + printk("PCI: Compaq host bridge: last bus %02x\n", busno2); + } } static void __init pci_fixup_umc_ide(struct pci_dev *d) @@ -924,6 +934,22 @@ pcibios_max_latency = 32; } +static void __init pci_fixup_vt8363(struct pci_dev *d) +{ + /* + * VIA VT8363 host bridge has broken feature 'PCI Master Read + * Caching'. It caches more than is good for it, sometimes + * serving the bus master with stale data. Some BIOSes enable + * it by default, so we disable it. + */ + u8 tmp; + pci_read_config_byte(d, 0x70, &tmp); + if(tmp & 4) { + printk("PCI: Bus master read caching disabled\n"); + pci_write_config_byte(d, 0x70, tmp & ~4); + } +} + struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx }, @@ -936,6 +962,7 @@ { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_vt8363 }, { 0 } }; diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.4.1/linux/arch/i386/kernel/process.c Thu Jan 4 12:50:17 2001 +++ linux/arch/i386/kernel/process.c Fri Feb 9 11:29:44 2001 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.4.1/linux/arch/i386/kernel/setup.c Sat Feb 3 19:51:22 2001 +++ linux/arch/i386/kernel/setup.c Fri Feb 16 16:02:37 2001 @@ -71,7 +71,7 @@ #include #include #include -#include +#include #include #include #include @@ -1104,6 +1104,9 @@ /* * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in * order to identify the Cyrix CPU model after we're out of setup.c + * + * Actually since bugs.h doesnt even reference this perhaps someone should + * fix the documentation ??? */ unsigned char Cx86_dir0_msb __initdata = 0; @@ -1129,6 +1132,8 @@ * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old * BIOSes for compatability with DOS games. This makes the udelay loop * work correctly, and improves performance. + * + * FIXME: our newer udelay uses the tsc. We dont need to frob with SLOP */ extern void calibrate_delay(void) __init; @@ -1401,6 +1406,7 @@ wrmsr (0x1107, lo, hi); set_bit(X86_FEATURE_CX8, &c->x86_capability); + set_bit(X86_FEATURE_3DNOW, &c->x86_capability); get_model_name(c); display_cacheinfo(c); @@ -1565,12 +1571,10 @@ case 4: if ( c->x86 > 6 && dl ) { /* P4 family */ - if ( dl ) { - /* L3 cache */ - cs = 128 << (dl-1); - l3 += cs; - break; - } + /* L3 cache */ + cs = 128 << (dl-1); + l3 += cs; + break; } /* else same as 8 - fall through */ case 8: @@ -1870,8 +1874,34 @@ /* Detect Cyrix with disabled CPUID */ if ( c->x86 == 4 && test_cyrix_52div() ) { + unsigned char dir0, dir1; + strcpy(c->x86_vendor_id, "CyrixInstead"); c->x86_vendor = X86_VENDOR_CYRIX; + + /* Actually enable cpuid on the older cyrix */ + + /* Retrieve CPU revisions */ + + do_cyrix_devid(&dir0, &dir1); + + dir0>>=4; + + /* Check it is an affected model */ + + if (dir0 == 5 || dir0 == 3) + { + unsigned char ccr3, ccr4; + + printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n"); + cli(); + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ + ccr4 = getCx86(CX86_CCR4); + setCx86(CX86_CCR4, ccr4 | 0x80); /* enable cpuid */ + setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ + sti(); + } } else /* Detect NexGen with old hypercode */ @@ -1914,7 +1944,6 @@ (int *)&c->x86_vendor_id[4]); get_cpu_vendor(c); - /* Initialize the standard set of capabilities */ /* Note that the vendor-specific code below might override */ diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.4.1/linux/arch/i386/kernel/signal.c Sat Feb 3 19:51:22 2001 +++ linux/arch/i386/kernel/signal.c Tue Feb 13 13:15:04 2001 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.4.1/linux/arch/i386/kernel/smp.c Fri Dec 29 14:35:47 2000 +++ linux/arch/i386/kernel/smp.c Tue Feb 13 14:13:43 2001 @@ -4,7 +4,7 @@ * (c) 1995 Alan Cox, Building #3 * (c) 1998-99, 2000 Ingo Molnar * - * This code is released under the GNU public license version 2 or + * This code is released under the GNU General Public License version 2 or * later. */ diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c --- v2.4.1/linux/arch/i386/kernel/smpboot.c Sun Dec 31 10:26:18 2000 +++ linux/arch/i386/kernel/smpboot.c Tue Feb 13 14:13:43 2001 @@ -11,7 +11,7 @@ * Pentium Pro and Pentium-II/Xeon MP machines. * Original development of Linux SMP code supported by Caldera. * - * This code is released under the GNU public license version 2 or + * This code is released under the GNU General Public License version 2 or * later. * * Fixes @@ -389,6 +389,7 @@ */ if (test_bit(cpuid, &cpu_callout_map)) break; + rep_nop(); } if (!time_before(jiffies, timeout)) { diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.4.1/linux/arch/i386/kernel/traps.c Sat Feb 3 19:51:22 2001 +++ linux/arch/i386/kernel/traps.c Tue Feb 13 14:15:04 2001 @@ -127,6 +127,11 @@ printk("\n"); } +void show_trace_task(struct task_struct *tsk) +{ + show_trace(&tsk->thread.esp); +} + void show_stack(unsigned long * esp) { unsigned long *stack; diff -u --recursive --new-file v2.4.1/linux/arch/i386/kernel/visws_apic.c linux/arch/i386/kernel/visws_apic.c --- v2.4.1/linux/arch/i386/kernel/visws_apic.c Thu Jul 13 09:29:34 2000 +++ linux/arch/i386/kernel/visws_apic.c Fri Feb 9 11:29:44 2001 @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/i386/mm/extable.c linux/arch/i386/mm/extable.c --- v2.4.1/linux/arch/i386/mm/extable.c Wed Nov 10 08:31:37 1999 +++ linux/arch/i386/mm/extable.c Fri Feb 16 16:02:37 2001 @@ -4,6 +4,7 @@ #include #include +#include #include extern const struct exception_table_entry __start___ex_table[]; @@ -30,26 +31,32 @@ return 0; } +extern spinlock_t modlist_lock; + unsigned long search_exception_table(unsigned long addr) { - unsigned long ret; - + unsigned long ret = 0; + unsigned long flags; + #ifndef CONFIG_MODULES /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); - if (ret) return ret; + return ret; #else /* The kernel is the last "module" -- no need to treat it special. */ struct module *mp; + + spin_lock_irqsave(&modlist_lock, flags); for (mp = module_list; mp != NULL; mp = mp->next) { if (mp->ex_table_start == NULL) continue; ret = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr); - if (ret) return ret; + if (ret) + break; } + spin_unlock_irqrestore(&modlist_lock, flags); + return ret; #endif - - return 0; } diff -u --recursive --new-file v2.4.1/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.4.1/linux/arch/i386/mm/fault.c Sat Nov 11 19:01:11 2000 +++ linux/arch/i386/mm/fault.c Tue Feb 13 14:13:43 2001 @@ -81,7 +81,7 @@ /* * Unlock any spinlocks which will prevent us from getting the - * message out (timerlist_lock is aquired through the + * message out (timerlist_lock is acquired through the * console unblank code) */ void bust_spinlocks(void) diff -u --recursive --new-file v2.4.1/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.4.1/linux/arch/ia64/config.in Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/config.in Fri Feb 16 15:53:08 2001 @@ -70,7 +70,7 @@ if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC fi - bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM n + bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM define_bool CONFIG_DEVFS_DEBUG y define_bool CONFIG_DEVFS_FS y define_bool CONFIG_IA64_BRL_EMU y @@ -79,8 +79,8 @@ define_bool CONFIG_SGI_IOC3_ETH y define_bool CONFIG_PERCPU_IRQ y define_int CONFIG_CACHE_LINE_SHIFT 7 - bool ' Enable DISCONTIGMEM support' CONFIG_DISCONTIGMEM y - bool ' Enable NUMA support' CONFIG_NUMA y + bool ' Enable DISCONTIGMEM support' CONFIG_DISCONTIGMEM + bool ' Enable NUMA support' CONFIG_NUMA fi define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /proc/kcore. diff -u --recursive --new-file v2.4.1/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.4.1/linux/arch/ia64/ia32/sys_ia32.c Sat Feb 3 19:51:22 2001 +++ linux/arch/ia64/ia32/sys_ia32.c Fri Feb 9 11:29:44 2001 @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c --- v2.4.1/linux/arch/ia64/kernel/irq.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/irq.c Fri Feb 9 11:29:44 2001 @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ia64/kernel/irq_ia64.c linux/arch/ia64/kernel/irq_ia64.c --- v2.4.1/linux/arch/ia64/kernel/irq_ia64.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/irq_ia64.c Fri Feb 9 11:29:44 2001 @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include /* for rand_initialize_irq() */ #include diff -u --recursive --new-file v2.4.1/linux/arch/ia64/kernel/palinfo.c linux/arch/ia64/kernel/palinfo.c --- v2.4.1/linux/arch/ia64/kernel/palinfo.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/kernel/palinfo.c Fri Feb 16 15:53:08 2001 @@ -23,9 +23,6 @@ #include #include #include -#if defined(MODVERSIONS) -#include -#endif #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ia64/kernel/pci.c linux/arch/ia64/kernel/pci.c --- v2.4.1/linux/arch/ia64/kernel/pci.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/pci.c Fri Feb 9 11:29:44 2001 @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c --- v2.4.1/linux/arch/ia64/kernel/ptrace.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/ptrace.c Tue Feb 13 14:13:43 2001 @@ -447,7 +447,7 @@ * When new_bsp is zero and force_loadrs_to_zero is 1 (non-zero), * loadrs is set to 0, and the bspstore value is set to the old bsp * value. This will cause the stacked registers (r32 and up) to be - * obtained entirely from the the child's memory space rather than + * obtained entirely from the child's memory space rather than * from the kernel. (This makes it easier to write code for * modifying the stacked registers in multi-threaded programs.) * diff -u --recursive --new-file v2.4.1/linux/arch/ia64/kernel/unwind.c linux/arch/ia64/kernel/unwind.c --- v2.4.1/linux/arch/ia64/kernel/unwind.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/kernel/unwind.c Tue Feb 13 14:13:43 2001 @@ -5,7 +5,7 @@ /* * This file implements call frame unwind support for the Linux * kernel. Parsing and processing the unwind information is - * time-consuming, so this implementation translates the the unwind + * time-consuming, so this implementation translates the unwind * descriptors into unwind scripts. These scripts are very simple * (basically a sequence of assignments) and efficient to execute. * They are cached for later re-use. Each script is specific for a diff -u --recursive --new-file v2.4.1/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S --- v2.4.1/linux/arch/ia64/lib/copy_user.S Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/lib/copy_user.S Tue Feb 13 14:13:43 2001 @@ -518,7 +518,7 @@ // 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 + // Again this comes from the fact that if you crossed just for 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 diff -u --recursive --new-file v2.4.1/linux/arch/ia64/sn/io/klconflib.c linux/arch/ia64/sn/io/klconflib.c --- v2.4.1/linux/arch/ia64/sn/io/klconflib.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/klconflib.c Fri Feb 16 16:02:34 2001 @@ -511,7 +511,7 @@ moduleid_t kgm, pkgm; int kgs, pkgs; -#if defined(DEBUG) && (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1 || defined(CONFIG_IA64_GENERIC))) && defined(BRINGUP) +#if defined(DEBUG) && (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP) printf("find_gfxpipe(): PIPE: %s mod %M slot %d\n",lb?lb->brd_name:"!LBRD", lb->brd_module,lb->brd_slot); #endif diff -u --recursive --new-file v2.4.1/linux/arch/ia64/sn/io/klgraph_hack.c linux/arch/ia64/sn/io/klgraph_hack.c --- v2.4.1/linux/arch/ia64/sn/io/klgraph_hack.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/klgraph_hack.c Fri Feb 16 16:02:34 2001 @@ -139,7 +139,7 @@ uint64_t *tmp; volatile u32 *tmp32; -#ifdef 0 +#if 0 /* Preset some values */ /* Write IOERR clear to clear the CRAZY bit in the status */ tmp = (uint64_t *)0xc0000a0001c001f8; *tmp = (uint64_t)0xffffffff; diff -u --recursive --new-file v2.4.1/linux/arch/ia64/sn/io/l1.c linux/arch/ia64/sn/io/l1.c --- v2.4.1/linux/arch/ia64/sn/io/l1.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/l1.c Tue Feb 13 14:13:43 2001 @@ -1462,7 +1462,7 @@ isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR); } - /* uart interrupts were blocked at bedrock when the the interrupt + /* uart interrupts were blocked at bedrock when the interrupt * was initially answered; reenable them now */ intr_unblock_bit( sc->intr_cpu, UART_INTR ); @@ -2865,7 +2865,7 @@ /* - * _elscuart_flush flushes queued output to the the L1. + * _elscuart_flush flushes queued output to the L1. * This routine blocks until the queue is flushed. */ int diff -u --recursive --new-file v2.4.1/linux/arch/ia64/sn/io/pcibr.c linux/arch/ia64/sn/io/pcibr.c --- v2.4.1/linux/arch/ia64/sn/io/pcibr.c Thu Jan 4 15:25:55 2001 +++ linux/arch/ia64/sn/io/pcibr.c Fri Feb 16 16:02:34 2001 @@ -3753,7 +3753,7 @@ * completion interrupts will reach a CPU * after all DMA data has reached memory. * (Of course, there may be a few special - * drivers/controlers that explicitly manage + * drivers/controllers that explicitly manage * this ordering problem.) */ @@ -8609,7 +8609,7 @@ BRIDGE_ERRUPPR_ADDRMASK) << 32))); /* - * need to ensure that the xtalk adress in ioe + * need to ensure that the xtalk address in ioe * maps to PCI error address read from bridge. * How to convert PCI address back to Xtalk address ? * (better idea: convert XTalk address to PCI address @@ -9108,7 +9108,7 @@ #ifdef LITTLE_ENDIAN /* - * on sn-ia we need to twiddle the the addresses going out + * on sn-ia we need to twiddle the addresses going out * the pci bus because we use the unswizzled synergy space * (the alternative is to use the swizzled synergy space * and byte swap the data) diff -u --recursive --new-file v2.4.1/linux/arch/ia64/sn/io/xbow.c linux/arch/ia64/sn/io/xbow.c --- v2.4.1/linux/arch/ia64/sn/io/xbow.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/xbow.c Tue Feb 13 14:13:43 2001 @@ -314,7 +314,7 @@ /* * get the name of this xbow vertex and keep the info. - * This is needed during errors and interupts, but as + * This is needed during errors and interrupts, but as * long as we have it, we can use it elsewhere. */ s = dev_to_name(vhdl, devnm, MAXDEVNAME); diff -u --recursive --new-file v2.4.1/linux/arch/ia64/sn/io/xtalk.c linux/arch/ia64/sn/io/xtalk.c --- v2.4.1/linux/arch/ia64/sn/io/xtalk.c Thu Jan 4 13:00:15 2001 +++ linux/arch/ia64/sn/io/xtalk.c Tue Feb 13 14:13:43 2001 @@ -959,7 +959,7 @@ widget_info->w_einfo = 0; /* * get the name of this xwidget vertex and keep the info. - * This is needed during errors and interupts, but as + * This is needed during errors and interrupts, but as * long as we have it, we can use it elsewhere. */ s = dev_to_name(widget,devnm,MAXDEVNAME); diff -u --recursive --new-file v2.4.1/linux/arch/m68k/atari/hades-pci.c linux/arch/m68k/atari/hades-pci.c --- v2.4.1/linux/arch/m68k/atari/hades-pci.c Wed Jan 26 12:44:20 2000 +++ linux/arch/m68k/atari/hades-pci.c Tue Feb 13 14:13:43 2001 @@ -17,7 +17,7 @@ #if defined(CONFIG_PCI) && defined(CONFIG_HADES) -#include +#include #include #include @@ -372,6 +372,8 @@ */ bus = kmalloc(sizeof(struct pci_bus_info), GFP_KERNEL); + if (!bus) + return NULL; memset(bus, 0, sizeof(struct pci_bus_info)); /* diff -u --recursive --new-file v2.4.1/linux/arch/m68k/atari/stram.c linux/arch/m68k/atari/stram.c --- v2.4.1/linux/arch/m68k/atari/stram.c Mon Nov 27 17:57:34 2000 +++ linux/arch/m68k/atari/stram.c Fri Feb 9 11:29:44 2001 @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/m68k/bvme6000/rtc.c linux/arch/m68k/bvme6000/rtc.c --- v2.4.1/linux/arch/m68k/bvme6000/rtc.c Wed Jul 12 21:58:42 2000 +++ linux/arch/m68k/bvme6000/rtc.c Fri Feb 9 11:29:44 2001 @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/m68k/ifpsp060/src/fplsp.S linux/arch/m68k/ifpsp060/src/fplsp.S --- v2.4.1/linux/arch/m68k/ifpsp060/src/fplsp.S Fri Dec 29 14:07:20 2000 +++ linux/arch/m68k/ifpsp060/src/fplsp.S Tue Feb 13 14:13:42 2001 @@ -9963,7 +9963,7 @@ # ALGORITHM *********************************************************** # # An underflow should occur as the result of transcendental # # emulation in the 060FPLSP. Create an underflow by using "fmul" # -# and two very small numbers of appropriate sign so the the operating # +# and two very small numbers of appropriate sign so the operating # # system can log the event. # # # ######################################################################### @@ -10020,7 +10020,7 @@ # ALGORITHM *********************************************************** # # An overflow should occur as the result of transcendental # # emulation in the 060FPLSP. Create an overflow by using "fmul" # -# and two very lareg numbers of appropriate sign so the the operating # +# and two very lareg numbers of appropriate sign so the operating # # system can log the event. # # For t_ovfl_sc() we take special care not to lose the INEX2 bit. # # # diff -u --recursive --new-file v2.4.1/linux/arch/m68k/ifpsp060/src/fpsp.S linux/arch/m68k/ifpsp060/src/fpsp.S --- v2.4.1/linux/arch/m68k/ifpsp060/src/fpsp.S Fri Dec 29 14:07:20 2000 +++ linux/arch/m68k/ifpsp060/src/fpsp.S Tue Feb 13 14:13:42 2001 @@ -2944,7 +2944,7 @@ # The FPU is disabled and so we should really have taken the "Line # F Emulator" exception. So, here we create an 8-word stack frame # from our 4-word stack frame. This means we must calculate the length -# the the faulting instruction to get the "next PC". This is trivial for +# the faulting instruction to get the "next PC". This is trivial for # immediate operands but requires some extra work for fmovm dynamic # which can use most addressing modes. iea_disabled: diff -u --recursive --new-file v2.4.1/linux/arch/m68k/ifpsp060/src/isp.S linux/arch/m68k/ifpsp060/src/isp.S --- v2.4.1/linux/arch/m68k/ifpsp060/src/isp.S Fri Dec 29 14:07:20 2000 +++ linux/arch/m68k/ifpsp060/src/isp.S Tue Feb 13 14:13:43 2001 @@ -2516,7 +2516,7 @@ cmpi.b %d0, &0x7 # is src mode Dn or other? bgt.w mul64_memop # src is in memory -# multiplier operand in the the data register file. +# multiplier operand in the data register file. # must extract the register number and fetch the operand from the stack. mul64_regop: andi.w &0x7, %d0 # extract Dn diff -u --recursive --new-file v2.4.1/linux/arch/m68k/ifpsp060/src/pfpsp.S linux/arch/m68k/ifpsp060/src/pfpsp.S --- v2.4.1/linux/arch/m68k/ifpsp060/src/pfpsp.S Fri Dec 29 14:07:20 2000 +++ linux/arch/m68k/ifpsp060/src/pfpsp.S Tue Feb 13 14:13:43 2001 @@ -2943,7 +2943,7 @@ # The FPU is disabled and so we should really have taken the "Line # F Emulator" exception. So, here we create an 8-word stack frame # from our 4-word stack frame. This means we must calculate the length -# the the faulting instruction to get the "next PC". This is trivial for +# the faulting instruction to get the "next PC". This is trivial for # immediate operands but requires some extra work for fmovm dynamic # which can use most addressing modes. iea_disabled: diff -u --recursive --new-file v2.4.1/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c --- v2.4.1/linux/arch/m68k/kernel/bios32.c Wed Jan 26 12:44:20 2000 +++ linux/arch/m68k/kernel/bios32.c Fri Feb 9 11:29:44 2001 @@ -26,7 +26,7 @@ */ #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S --- v2.4.1/linux/arch/m68k/kernel/entry.S Mon Nov 27 18:02:06 2000 +++ linux/arch/m68k/kernel/entry.S Tue Feb 13 14:13:43 2001 @@ -140,7 +140,7 @@ bnes 2f | if so, skip resched, signals | only allow interrupts when we are really the last one on the | kernel stack, otherwise stack overflow can occur during - | heavy interupt load + | heavy interrupt load andw #ALLOWINT,%sr tstl %curptr@(TASK_NEEDRESCHED) jne SYMBOL_NAME(reschedule) diff -u --recursive --new-file v2.4.1/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c --- v2.4.1/linux/arch/m68k/kernel/process.c Tue Sep 5 13:50:01 2000 +++ linux/arch/m68k/kernel/process.c Fri Feb 9 11:29:44 2001 @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/m68k/mac/misc.c linux/arch/m68k/mac/misc.c --- v2.4.1/linux/arch/m68k/mac/misc.c Mon Sep 11 08:39:48 2000 +++ linux/arch/m68k/mac/misc.c Fri Feb 9 11:29:44 2001 @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/m68k/mac/oss.c linux/arch/m68k/mac/oss.c --- v2.4.1/linux/arch/m68k/mac/oss.c Sun Dec 3 17:48:19 2000 +++ linux/arch/m68k/mac/oss.c Tue Feb 13 14:13:43 2001 @@ -123,7 +123,7 @@ /* * Nubus IRQ handler, OSS style * - * Unlike the VIA/RBV this is on its own autovector interupt level. + * Unlike the VIA/RBV this is on its own autovector interrupt level. */ void oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs) diff -u --recursive --new-file v2.4.1/linux/arch/m68k/math-emu/fp_cond.S linux/arch/m68k/math-emu/fp_cond.S --- v2.4.1/linux/arch/m68k/math-emu/fp_cond.S Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/math-emu/fp_cond.S Tue Feb 13 14:13:43 2001 @@ -17,7 +17,7 @@ * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are + * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) diff -u --recursive --new-file v2.4.1/linux/arch/m68k/math-emu/fp_decode.h linux/arch/m68k/math-emu/fp_decode.h --- v2.4.1/linux/arch/m68k/math-emu/fp_decode.h Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/math-emu/fp_decode.h Tue Feb 13 14:13:43 2001 @@ -17,7 +17,7 @@ * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are + * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) diff -u --recursive --new-file v2.4.1/linux/arch/m68k/math-emu/fp_emu.h linux/arch/m68k/math-emu/fp_emu.h --- v2.4.1/linux/arch/m68k/math-emu/fp_emu.h Wed Nov 10 10:00:48 1999 +++ linux/arch/m68k/math-emu/fp_emu.h Tue Feb 13 14:13:43 2001 @@ -17,7 +17,7 @@ * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are + * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) diff -u --recursive --new-file v2.4.1/linux/arch/m68k/math-emu/fp_entry.S linux/arch/m68k/math-emu/fp_entry.S --- v2.4.1/linux/arch/m68k/math-emu/fp_entry.S Fri Nov 12 04:29:47 1999 +++ linux/arch/m68k/math-emu/fp_entry.S Tue Feb 13 14:13:43 2001 @@ -17,7 +17,7 @@ * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are + * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) diff -u --recursive --new-file v2.4.1/linux/arch/m68k/math-emu/fp_move.S linux/arch/m68k/math-emu/fp_move.S --- v2.4.1/linux/arch/m68k/math-emu/fp_move.S Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/math-emu/fp_move.S Tue Feb 13 14:13:43 2001 @@ -17,7 +17,7 @@ * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are + * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) diff -u --recursive --new-file v2.4.1/linux/arch/m68k/math-emu/fp_movem.S linux/arch/m68k/math-emu/fp_movem.S --- v2.4.1/linux/arch/m68k/math-emu/fp_movem.S Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/math-emu/fp_movem.S Tue Feb 13 14:13:43 2001 @@ -17,7 +17,7 @@ * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are + * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) diff -u --recursive --new-file v2.4.1/linux/arch/m68k/math-emu/fp_scan.S linux/arch/m68k/math-emu/fp_scan.S --- v2.4.1/linux/arch/m68k/math-emu/fp_scan.S Sun Aug 15 11:47:29 1999 +++ linux/arch/m68k/math-emu/fp_scan.S Tue Feb 13 14:13:43 2001 @@ -17,7 +17,7 @@ * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are + * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) diff -u --recursive --new-file v2.4.1/linux/arch/m68k/math-emu/fp_util.S linux/arch/m68k/math-emu/fp_util.S --- v2.4.1/linux/arch/m68k/math-emu/fp_util.S Fri Nov 12 04:29:47 1999 +++ linux/arch/m68k/math-emu/fp_util.S Tue Feb 13 14:13:43 2001 @@ -17,7 +17,7 @@ * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU Public License, in which case the provisions of the GPL are + * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) diff -u --recursive --new-file v2.4.1/linux/arch/m68k/mm/kmap.c linux/arch/m68k/mm/kmap.c --- v2.4.1/linux/arch/m68k/mm/kmap.c Wed Jan 26 12:44:20 2000 +++ linux/arch/m68k/mm/kmap.c Fri Feb 9 11:29:44 2001 @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c --- v2.4.1/linux/arch/m68k/mm/memory.c Mon Aug 7 21:02:27 2000 +++ linux/arch/m68k/mm/memory.c Fri Feb 9 11:29:44 2001 @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/m68k/mvme16x/rtc.c linux/arch/m68k/mvme16x/rtc.c --- v2.4.1/linux/arch/m68k/mvme16x/rtc.c Wed Jul 12 21:58:42 2000 +++ linux/arch/m68k/mvme16x/rtc.c Fri Feb 9 11:29:44 2001 @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/baget/irq.c linux/arch/mips/baget/irq.c --- v2.4.1/linux/arch/mips/baget/irq.c Fri Aug 4 16:15:37 2000 +++ linux/arch/mips/baget/irq.c Fri Feb 9 11:29:44 2001 @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/baget/vacserial.c linux/arch/mips/baget/vacserial.c --- v2.4.1/linux/arch/mips/baget/vacserial.c Thu Oct 12 14:20:48 2000 +++ linux/arch/mips/baget/vacserial.c Fri Feb 9 11:29:44 2001 @@ -56,7 +56,7 @@ #include #include #include -#include +#include #include #include #ifdef CONFIG_SERIAL_CONSOLE diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/Makefile linux/arch/mips/cobalt/Makefile --- v2.4.1/linux/arch/mips/cobalt/Makefile Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/cobalt/Makefile Wed Dec 31 16:00:00 1969 @@ -1,24 +0,0 @@ -# -# Makefile for the Cobalt micro systems family specific parts of the kernel -# -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). -# -# $Id: Makefile,v 1.1 1997/10/23 22:25:41 ralf Exp $ -# - -.S.s: - $(CPP) $(CFLAGS) $< -o $*.s -.S.o: - $(CC) $(CFLAGS) -c $< -o $*.o - -all: cobalt.o -O_TARGET := cobalt.o -O_OBJS := cobaltscc.o hw-access.o int-handler.o pci.o reset.o setup.o via.o - -int-handler.o: int-handler.S - -clean: - -include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/cobaltscc.c linux/arch/mips/cobalt/cobaltscc.c --- v2.4.1/linux/arch/mips/cobalt/cobaltscc.c Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/cobalt/cobaltscc.c Wed Dec 31 16:00:00 1969 @@ -1,350 +0,0 @@ -/* - * Filename: cobaltscc.c - * - * Description: Functions for supporting and testing serial I/O - * - * Author(s): Timothy Stonis - * - * Copyright 1997, Cobalt Microserver, Inc. - */ -#include "z8530.h" -#include "diagdefs.h" -#include "serial.h" -#include "asm/io.h" - -/* - * Function prototypes - */ -void InitSerialPort(unsigned char *); -void RegisterDelay(void); -void InitScc(void); - -/* - * Function: RegisterDelay - * - * Description: A little delay since the SCC can't handle quick consecutive - * accesses - * In: none - * Out: none - */ -void RegisterDelay(void) -{ - register int ctr; - - for(ctr=0;ctr<0x40;ctr++); -} - -/* - * Function: SccInit - * - * Description: Initialize all the SCC registers for 19200 baud, asynchronous, - * 8 bit, 1 stop bit, no parity communication (Channel A) - * - * In: none - * - * Out: none - */ -void InitScc(void) -{ - /* Force hardware reset */ - Write8530(kSCC_ChanA | kSCC_Command, R9 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, FHWRES); - RegisterDelay(); - - /* x32 clock, 1 stop bit, no parity */ - Write8530(kSCC_ChanA | kSCC_Command, R4 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, X16CLK | SB1); - RegisterDelay(); - - /* Rx 8 bits, Rx disabled */ - Write8530(kSCC_ChanA | kSCC_Command, R3 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, Rx8); - RegisterDelay(); - - /* Tx 8 bits, DTR, RTS, Tx off */ - Write8530(kSCC_ChanA | kSCC_Command, R5 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, Tx8 | DTR | RTS); - RegisterDelay(); - - /* Int. Disabled */ - Write8530(kSCC_ChanA | kSCC_Command, R9 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, 0x0); - RegisterDelay(); - - /* NRZ */ - Write8530(kSCC_ChanA | kSCC_Command, R10 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, NRZ); - RegisterDelay(); - - /* Tx & Rx = BRG out, TRxC = BRG out */ - Write8530(kSCC_ChanA | kSCC_Command, R11 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, TCBR | RCBR | TRxCBR | TRxCOI); - RegisterDelay(); - - /* Time constant = 0x01 */ - Write8530(kSCC_ChanA | kSCC_Command, R12 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, kSCC_115200 ); - RegisterDelay(); - - /* Time constant high = 0x00 */ - Write8530(kSCC_ChanA | kSCC_Command, R13 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, 0x00); - RegisterDelay(); - - /* BRG in = ~RTxC, BRG off, loopback */ - Write8530(kSCC_ChanA | kSCC_Command, R14 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, LOOPBAK | BRSRC); - RegisterDelay(); -} - -/* - * Function: EnableScc - * - * Description: Enable transmit and receive on SCC Channel A - * In: none - * Out: none - */ -void EnableScc(void) -{ - /* Enable BRG */ - Write8530(kSCC_ChanA | kSCC_Command, R14 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, BRENABL | BRSRC); - RegisterDelay(); - - /* Rx enable (Rx 8 bits) */ - Write8530(kSCC_ChanA | kSCC_Command, R3 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, RxENABLE | Rx8); - RegisterDelay(); - - /* Tx enable (Tx8, DTR, RTS) */ - Write8530(kSCC_ChanA | kSCC_Command, R5 | NULLCODE); - RegisterDelay(); - Write8530(kSCC_ChanA, TxENAB | Tx8 | DTR | RTS); - RegisterDelay(); -} - -/* - * Function: SccOutb - * - * Description: Write a byte to the SCC (Channel A) and blink LED - * In: Byte to send - * Out: none - */ -void SccOutb(unsigned char byte) -{ - /* LED on.. */ - Write8530(kSCC_ChanB | kSCC_Command, R5); - RegisterDelay(); - Write8530(kSCC_ChanB | kSCC_Command, RTS); - RegisterDelay(); - - while ((Read8530(kSCC_ChanA) & Tx_BUF_EMP) == 0) - RegisterDelay(); - - Write8530(kSCC_ChanA | kSCC_Direct, byte); - RegisterDelay(); - - /* LED off.. */ - Write8530(kSCC_ChanB | kSCC_Command, R9); - RegisterDelay(); - Write8530(kSCC_ChanB | kSCC_Command, CHRB); - RegisterDelay(); -} - -/* - * Function: SccInb - * - * Description: Read a byte from the SCC (Channel A) - * In: Byte to send - * Out: none - */ -void SccInb(unsigned char *byte) -{ - while ((Read8530(kSCC_ChanA) & Rx_CH_AV) == 0) - RegisterDelay(); - - *byte = Read8530(kSCC_ChanA | kSCC_Direct); - RegisterDelay(); -} - -/* - * Function: SccWrite - * - * Description: Write a null terminated string to the SCC - * In: C string - * Out: none - */ -void SccWrite(const unsigned char *string) -{ - while((*string) != 0) { - if (*string == 10) - SccOutb((unsigned char) 13); - SccOutb(*(string++)); - } -} - -/* - * Function: InitSerialPort - * - * Description: Initialize the SCC and spit out the header message - * In: Header message - * Out: none - */ -void InitSerialPort(unsigned char *msg) -{ - InitScc(); - EnableScc(); - SccWrite(msg); -} - -/* - * Function: SccInbTimeout - * - * Description: Read a byte from the SCC (Channel A) with timeout - * In: Byte to send - * Out: Timeout status - */ -unsigned char SccInbTimeout(unsigned char *byte, unsigned long timeout) -{ - unsigned long ctr = 0; - - while ((Read8530(kSCC_ChanA) & Rx_CH_AV) == 0) { - RegisterDelay(); - if ((ctr++) > timeout) - return 0xFF; - } - - *byte = Read8530(kSCC_ChanA | kSCC_Direct); - RegisterDelay(); - - return 0; -} - -#include - -extern int serial_echo_init (int base); -extern int serial_echo_print (const char *s); - -/* - * this defines the address for the port to which printk echoing is done - * when CONFIG_SERIAL_ECHO is defined - */ -#define SERIAL_ECHO_PORT 0x1C800000 - -static int serial_echo_port = 0; - -#define serial_echo_outb(v,a) outb((v),(a)+serial_echo_port) -#define serial_echo_inb(a) inb((a)+serial_echo_port) - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* Wait for transmitter & holding register to empty */ -#define WAIT_FOR_XMITR \ - do { \ - lsr = serial_echo_inb(UART_LSR); \ - } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY) - -/* - * These two functions abstract the actual communications with the - * debug port. This is so we can change the underlying communications - * mechanism without modifying the rest of the code. - */ -int -serial_echo_print(const char *s) -{ - int lsr, ier; - int i; - - if (!serial_echo_port) - return 0; - - /* - * First save the IER then disable the interrupts - */ - ier = serial_echo_inb(UART_IER); - serial_echo_outb(0x00, UART_IER); - - /* - * Now, do each character - */ - for (i = 0; *s; i++, s++) { - WAIT_FOR_XMITR; - - /* Send the character out. */ - serial_echo_outb(*s, UART_TX); - - /* if a LF, also do CR... */ - if (*s == 10) { - WAIT_FOR_XMITR; - serial_echo_outb(13, UART_TX); - } - } - - /* - * Finally, Wait for transmitter & holding register to empty - * and restore the IER - */ - do { - lsr = serial_echo_inb(UART_LSR); - } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY); - serial_echo_outb(ier, UART_IER); - - return 0; -} - - -int -serial_echo_init(int base) -{ - int comstat, hi, lo; - - serial_echo_port = base; - - /* - * read the Divisor Latch - */ - comstat = serial_echo_inb(UART_LCR); - serial_echo_outb(comstat | UART_LCR_DLAB, UART_LCR); - hi = serial_echo_inb(UART_DLM); - lo = serial_echo_inb(UART_DLL); - serial_echo_outb(comstat, UART_LCR); - - /* - * now do hardwired init - */ - serial_echo_outb(0x03, UART_LCR); /* No parity, 8 data bits, 1 stop */ - serial_echo_outb(0x83, UART_LCR); /* Access divisor latch */ - - /* This is computed using: - * - * const BASE_BAUD = (18432000 / 16); - * UART_DLM = (BASE_BAUD / baud_I_want) >> 8; - * UART_DLL = (BASE_BAUD / baud_I_want) & 0xff; - */ - serial_echo_outb(0x00, UART_DLM); /* 115200 baud */ - serial_echo_outb(0x0A, UART_DLL); - - serial_echo_outb(0x03, UART_LCR); /* Done with divisor */ - - /* - * Prior to disabling interrupts, read the LSR and RBR - * registers - */ - comstat = serial_echo_inb(UART_LSR); /* COM? LSR */ - comstat = serial_echo_inb(UART_RX); /* COM? RBR */ - serial_echo_outb(0x00, UART_IER); /* Disable all interrupts */ - - return 0; -} diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/diagdefs.h linux/arch/mips/cobalt/diagdefs.h --- v2.4.1/linux/arch/mips/cobalt/diagdefs.h Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/cobalt/diagdefs.h Wed Dec 31 16:00:00 1969 @@ -1,177 +0,0 @@ -/* - * Filename: diagdefs.h - * - * Description: Some general definitions used by the diagnostics - * - * Author(s): Timothy Stonis - * - * Copyright 1997, Cobalt Microserver, Inc. - */ - -#define KSEG0_Base 0x80000000 -#define KSEG1_Base 0xA0000000 - -// Some useful Galileo registers/base addresses (boot time kseg1 mapping) -#define kGal_InternalBase ( 0x14000000 | KSEG1_Base ) -#define kGal_DevBank0Base ( 0x1C000000 | KSEG1_Base ) -#define kGal_DevBank1Base ( 0x1C800000 | KSEG1_Base ) - -#define kGal_RAS10Lo 0x008 -#define kGal_RAS10Hi 0x010 -#define kGal_RAS32Lo 0x018 -#define kGal_RAS32Hi 0x020 - -#define kGal_PCIIOLo 0x048 -#define kGal_PCIIOHi 0x050 - -#define kGal_RAS10LoCfg 0x000 -#define kGal_RAS10HiCfg 0x03 -#define kGal_RAS32LoCfg 0x004 -#define kGal_RAS32HiCfg 0x07 - -#define kGal_PCIIOLoCfg 0x000 -#define kGal_PCIIOHiCfg 0x0F - - -#define kGal_DevBank0PReg 0x45C -#define kGal_DevBank1PReg 0x460 -#define kGal_DevBank2PReg 0x464 -#define kGal_DevBank3PReg 0x468 -#define kGal_DevBankBPReg 0x46C - -#define kGal_DRAMCReg 0x448 -#define kGal_DRAM0PReg 0x44C -#define kGal_DRAM1PReg 0x450 -#define kGal_DRAM2PReg 0x454 -#define kGal_DRAM3PReg 0x458 - -#define kGal_ConfigAddr 0xCF8 -#define kGal_ConfigData 0xCFC -#define kGal_PCICfgEn 0x1F // Generate config cycle -#define kGal_DevNum 0x00 // Technically 0x06, but 0 works too -#define kGal_MasMemEn 0x06 -#define kGal_Latency 0x700 - -#define kGal_RAS01StartReg 0x10 -#define kGal_RAS23StartReg 0x14 -#define kGal_RAS01SizeReg 0x0C08 -#define kGal_RAS23SizeReg 0x0C0C - - -#define kGal_RAS01Start 0x000 -#define kGal_RAS23Start 0x00800000 -#define kGal_RAS01Size 0x007FFFFF -#define kGal_RAS23Size 0x007FFFFF - - -// Paramter information for devices, DRAM, etc -#define kGal_DevBank0Cfg 0x1446DB33 -#define kGal_DevBank1Cfg 0x144FE667 -#define kGal_DevBankBCfg 0x1446DC43 -#define kGal_DRAMConfig 0x00000300 -#define kGal_DRAM0Config 0x00000010 -#define kGal_DRAM1Config 0x00000010 -#define kGal_DRAM2Config 0x00000010 -#define kGal_DRAM3Config 0x00000010 - -#define kGal_DRAM0Hi 0x00000003 -#define kGal_DRAM0Lo 0x00000000 -#define kGal_DRAM1Hi 0x00000007 -#define kGal_DRAM1Lo 0x00000004 -#define kGal_DRAM2Hi 0x0000000B -#define kGal_DRAM2Lo 0x00000008 -#define kGal_DRAM3Hi 0x0000000F -#define kGal_DRAM3Lo 0x0000000C - -#define kGal_RAS0Lo 0x400 -#define kGal_RAS0Hi 0x404 -#define kGal_RAS1Lo 0x408 -#define kGal_RAS1Hi 0x40C -#define kGal_RAS2Lo 0x410 -#define kGal_RAS2Hi 0x414 -#define kGal_RAS3Lo 0x418 -#define kGal_RAS3Hi 0x41C - -// Feedback LED indicators during setup code (reset.S, main.c) -#define kLED_AllOn 0x0F -#define kLED_FlashTest 0x01 -#define kLED_MemTest 0x02 -#define kLED_SCCTest 0x03 -#define kLED_GalPCI 0x04 -#define kLED_EnetTest 0x05 -#define kLED_SCSITest 0x06 -#define kLED_IOCTest 0x07 -#define kLED_Quickdone 0x0A -#define kLED_Exception 0x0B -#define kLED_ProcInit 0x0E -#define kLED_AllOff 0x00 - -#define kLEDBase kGal_DevBank0Base - -// Some memory related constants -#define kRAM_Start (0x00000000 | KSEG0_Base) - -#define kTestPat1 0xA5A5A5A5 -#define kTestPat2 0x5A5A5A5A - -#define k1Meg_kseg1 (0x00100000 | KSEG0_Base) -#define k2Meg_kseg1 (0x00200000 | KSEG0_Base) -#define k4Meg_kseg1 (0x00400000 | KSEG0_Base) -#define k8Meg_kseg1 (0x00800000 | KSEG0_Base) -#define k16Meg_kseg1 (0x01000000 | KSEG0_Base) - -#define kInit_SP k4Meg_kseg1 - 0x100 -#define kVectorBase 0x200 -#define kDebugVectors 0x400 -#define kMallocCheese 0x80E00000 -#define kDecompAddr 0x80700000 -#define kCompAddr 0x80500000 - - -// Ethernet definitions -#define kEnet_VIOBase ( 0x12100000 | KSEG1_Base ) -#define kEnet_PIOBase 0x12100000 -#define kEnet_CSCfg 0x46 -#define kEnet_DevNum 0x07 -#define kEnet_CSR3 0x18 -#define kEnet_CSR15 0x78 - - -#define kEnet_GEPOut 0x080f0000 -#define kEnet_GEPOn 0x000f0000 - - -// SCSI definitions -#define kSCSI_VIOBase ( 0x12200000 | KSEG1_Base ) -#define kSCSI_PIOBase 0x12200000 -#define kSCSI_CSCfg 0x46 -#define kSCSI_DevNum 0x08 -#define kSCSI_GPCNTL 0x47 -#define kSCSI_GPREG 0x07 -#define kSCSI_SCRTCHA 0x34 - -#define kSCSI_GPIOOut 0x0C -#define kSCSI_LEDsOn 0x00 - -// I/O Controller definitions -#define kIOC_VIOBase ( 0x10000000 | KSEG1_Base ) -#define kIOC_RIOBase 0x10000000 -#define kIOC_DevNum 0x09 -#define kIOC_ISAFunc 0x00 -#define kIOC_IDEFunc 0x01 -#define kIOC_USBFunc 0x02 -#define kIOC_MiscC0 0x44 -#define kIOC_IDEEnable 0x40 - -#define kIOC_PCIIDEOn 0x02800085 -#define kIOC_PriIDEOn 0x0A - -// Some PCI Definitions -#define kPCI_StatCmd 0x04 -#define kPCI_LatCache 0x0C -#define kPCI_CBIO 0x10 -#define kPCI_CBMEM 0x14 - -// Random constants -#define kBogoSec 0x0003F940 -#define kSCCDelay 0x00000001 diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/hw-access.c linux/arch/mips/cobalt/hw-access.c --- v2.4.1/linux/arch/mips/cobalt/hw-access.c Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/cobalt/hw-access.c Wed Dec 31 16:00:00 1969 @@ -1,58 +0,0 @@ -/* - * Low-level hardware access stuff for Cobalt Microserver 27 board. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1995, 1996, 1997 by Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include - -void -dummy(void) -{ - panic("What the hell is this called for?"); -} - -static unsigned char cobalt_read_cmos(unsigned long reg) -{ - unsigned char retval; - - VIA_PORT_WRITE(0x70, reg); - retval = VIA_PORT_READ(0x71); - VIA_DELAY(); - - return retval; -} - -static void cobalt_write_cmos(unsigned char val, unsigned long reg) -{ - VIA_PORT_WRITE(0x70, reg); - VIA_PORT_WRITE(0x71, val); -} - -struct feature cobalt_feature = { - /* - * How to access the floppy controller's ports - */ - (void *)dummy, (void *)dummy, - /* - * How to access the floppy DMA functions. - */ - (void *)dummy, (void *)dummy, (void *)dummy, (void *)dummy, - (void *)dummy, (void *)dummy, (void *)dummy, (void *)dummy, - (void *)dummy, (void *)dummy, (void *)dummy, - /* - * How to access the RTC functions. - */ - cobalt_read_cmos, - cobalt_write_cmos -}; diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/int-handler.S linux/arch/mips/cobalt/int-handler.S --- v2.4.1/linux/arch/mips/cobalt/int-handler.S Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/cobalt/int-handler.S Wed Dec 31 16:00:00 1969 @@ -1,140 +0,0 @@ -/* - * arch/mips/cobalt/int-handler.S - */ -#include -#include -#include -#include -#include -#include -#include - -/* - * cobalt_handle_int: Interrupt handler for the twenty-seven board. - */ - .align 5 - .set noreorder - NESTED(cobalt_handle_int, PT_SIZE, ra) - .set noat - SAVE_ALL - REG_S sp,PT_OR2(sp) - CLI - .set at - mfc0 t0,CP0_CAUSE - mfc0 t1,CP0_STATUS - and t0,t1 - xor t1,t0 - mtc0 t1,CP0_STATUS # mask all active ints - /* Such a kind of cascade is optimal for R5000 */ - - andi t1,t0,STATUSF_IP2 - bnez t1,ll_galileo_irq - andi t1,t0,STATUSF_IP3 - bnez t1,ll_ethernet0_irq -/* - * This should be conditional, and not used for the cube-1, but - * there is not a config flag that is useful. - */ - - andi t1,t0,STATUSF_IP4 - bnez t1,ll_ethernet1_irq -/* #endif */ - andi t1,t0,STATUSF_IP6 - bnez t1,ll_via_irq - andi t1,t0,STATUSF_IP5 - bnez t1,ll_serial_irq - andi t1,t0,STATUSF_IP7 - bnez t1,ll_pci_irq - nop - /* wrong alarm ... */ - j spurious_interrupt - nop - END(cobalt_handle_int) - - - .align 5 - .set reorder -ll_galileo_irq: move a0,sp - INC_INTR_COUNT(s1,s2) - jal galileo_irq - nop - DEC_INTR_COUNT(s1,s2) - j ret_from_irq - nop - - .align 5 - .set reorder -ll_via_irq: move a0,sp - INC_INTR_COUNT(s1,s2) - jal via_irq - nop - DEC_INTR_COUNT(s1,s2) - j ret_from_irq - nop - - .align 5 - .set reorder -ll_ethernet0_irq: - INC_INTR_COUNT(s1,s2) - mfc0 s0,CP0_STATUS # mask interrupt - ori t0,s0,(STATUSF_IP3 | STATUSF_IP4) - xori t0,(STATUSF_IP3 | STATUSF_IP4) - mtc0 t0,CP0_STATUS - li a0,4 - move a1,sp - jal do_IRQ - nop - mtc0 s0,CP0_STATUS - DEC_INTR_COUNT(s1,s2) - j ret_from_irq - nop - - .align 5 - .set reorder -ll_serial_irq: li a0,7 - INC_INTR_COUNT(s1,s2) - move a1,sp - jal do_IRQ - nop - DEC_INTR_COUNT(s1,s2) - j ret_from_irq - nop - - - .align 5 - .set reorder -ll_ethernet1_irq: - INC_INTR_COUNT(s1,s2) - mfc0 s0,CP0_STATUS # mask interrupt - - ori t0,s0, (STATUSF_IP3 | STATUSF_IP4) - xori t0,(STATUSF_IP3 | STATUSF_IP4) - - mtc0 t0,CP0_STATUS - li a0,13 - move a1,sp - jal do_IRQ - nop - mtc0 s0,CP0_STATUS - DEC_INTR_COUNT(s1,s2) - j ret_from_irq - nop - - # - # This is pretty weird. The "pci" interrupt on the hardware - # skematic is from the PCI side of the galileo, so we would - # only get interrupts here if WE write the control register - # that normally enables the cpu to send interrupts to the PCI. - # - # If you want to interrupt a PCI card, look elsewhere. - # - .align 5 - .set reorder -ll_pci_irq: li a0,7 - INC_INTR_COUNT(s1,s2) - move a1,sp - jal do_IRQ - nop - DEC_INTR_COUNT(s1,s2) - j ret_from_irq - nop diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/pci.c linux/arch/mips/cobalt/pci.c --- v2.4.1/linux/arch/mips/cobalt/pci.c Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/cobalt/pci.c Wed Dec 31 16:00:00 1969 @@ -1,348 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Cobalt Qube specific PCI support. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#undef PCI_DEBUG - -#ifdef CONFIG_PCI - -static void qube_expansion_slot_bist(void) -{ - unsigned char ctrl; - int timeout = 100000; - - pcibios_read_config_byte(0, (0x0a<<3), PCI_BIST, &ctrl); - if(!(ctrl & PCI_BIST_CAPABLE)) - return; - - pcibios_write_config_byte(0, (0x0a<<3), PCI_BIST, ctrl|PCI_BIST_START); - do { - pcibios_read_config_byte(0, (0x0a<<3), PCI_BIST, &ctrl); - if(!(ctrl & PCI_BIST_START)) - break; - } while(--timeout > 0); - if((timeout <= 0) || (ctrl & PCI_BIST_CODE_MASK)) - printk("PCI: Expansion slot card failed BIST with code %x\n", - (ctrl & PCI_BIST_CODE_MASK)); -} - -static void qube_expansion_slot_fixup(void) -{ - unsigned short pci_cmd; - unsigned long ioaddr_base = 0x10108000; /* It's magic, ask Doug. */ - unsigned long memaddr_base = 0x12000000; - int i; - - /* Enable bits in COMMAND so driver can talk to it. */ - pcibios_read_config_word(0, (0x0a<<3), PCI_COMMAND, &pci_cmd); - pci_cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - pcibios_write_config_word(0, (0x0a<<3), PCI_COMMAND, pci_cmd); - - /* Give it a working IRQ. */ - pcibios_write_config_byte(0, (0x0a<<3), PCI_INTERRUPT_LINE, 9); - - /* Fixup base addresses, we only support I/O at the moment. */ - for(i = 0; i <= 5; i++) { - unsigned int regaddr = (PCI_BASE_ADDRESS_0 + (i * 4)); - unsigned int rval, mask, size, alignme, aspace; - unsigned long *basep = &ioaddr_base; - - /* Check type first, punt if non-IO. */ - pcibios_read_config_dword(0, (0x0a<<3), regaddr, &rval); - aspace = (rval & PCI_BASE_ADDRESS_SPACE); - if(aspace != PCI_BASE_ADDRESS_SPACE_IO) - basep = &memaddr_base; - - /* Figure out how much it wants, if anything. */ - pcibios_write_config_dword(0, (0x0a<<3), regaddr, 0xffffffff); - pcibios_read_config_dword(0, (0x0a<<3), regaddr, &rval); - - /* Unused? */ - if(rval == 0) - continue; - - rval &= PCI_BASE_ADDRESS_IO_MASK; - mask = (~rval << 1) | 0x1; - size = (mask & rval) & 0xffffffff; - alignme = size; - if(alignme < 0x400) - alignme = 0x400; - rval = ((*basep + (alignme - 1)) & ~(alignme - 1)); - *basep = (rval + size); - pcibios_write_config_dword(0, (0x0a<<3), regaddr, rval | aspace); - } - qube_expansion_slot_bist(); -} - -static void qube_raq_tulip_fixup(void) -{ - unsigned short pci_cmd; - - /* Enable the device. */ - pcibios_read_config_word(0, (0x0c<<3), PCI_COMMAND, &pci_cmd); - pci_cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MASTER); - pcibios_write_config_word(0, (0x0c<<3), PCI_COMMAND, pci_cmd); - - /* Give it it's IRQ. */ - /* NOTE: RaQ board #1 has a bunch of green wires which swapped the - * IRQ line values of Tulip 0 and Tulip 1. All other - * boards have eth0=4,eth1=13. -DaveM - */ -#ifndef RAQ_BOARD_1_WITH_HWHACKS - pcibios_write_config_byte(0, (0x0c<<3), PCI_INTERRUPT_LINE, 13); -#else - pcibios_write_config_byte(0, (0x0c<<3), PCI_INTERRUPT_LINE, 4); -#endif - - /* And finally, a usable I/O space allocation, right after what - * the first Tulip uses. - */ - pcibios_write_config_dword(0, (0x0c<<3), PCI_BASE_ADDRESS_0, 0x10101001); -} - -static void qube_raq_scsi_fixup(void) -{ - unsigned short pci_cmd; - - /* Enable the device. */ - pcibios_read_config_word(0, (0x08<<3), PCI_COMMAND, &pci_cmd); - - pci_cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY - | PCI_COMMAND_INVALIDATE); - pcibios_write_config_word(0, (0x08<<3), PCI_COMMAND, pci_cmd); - - /* Give it it's IRQ. */ - pcibios_write_config_byte(0, (0x08<<3), PCI_INTERRUPT_LINE, 4); - - /* And finally, a usable I/O space allocation, right after what - * the second Tulip uses. - */ - pcibios_write_config_dword(0, (0x08<<3), PCI_BASE_ADDRESS_0, 0x10102001); - pcibios_write_config_dword(0, (0x08<<3), PCI_BASE_ADDRESS_1, 0x00002000); - pcibios_write_config_dword(0, (0x08<<3), PCI_BASE_ADDRESS_2, 0x00100000); -} - -static unsigned long -qube_pcibios_fixup(unsigned long mem_start, unsigned long mem_end) -{ - extern int cobalt_is_raq; - int raq_p = cobalt_is_raq; - unsigned int tmp; - - /* Fixup I/O and Memory space decoding on Galileo. */ - isa_slot_offset = COBALT_LOCAL_IO_SPACE; - - /* Fix PCI latency-timer and cache-line-size values in Galileo - * host bridge. - */ - pcibios_write_config_byte(0, 0, PCI_LATENCY_TIMER, 64); - pcibios_write_config_byte(0, 0, PCI_CACHE_LINE_SIZE, 7); - - /* - * Now tell the SCSI device that we expect an interrupt at - * IRQ 7 and not the default 0. - */ - pcibios_write_config_byte(0, 0x08<<3, PCI_INTERRUPT_LINE, - COBALT_SCSI_IRQ); - - /* - * Now tell the Ethernet device that we expect an interrupt at - * IRQ 13 and not the default 189. - * - * The IRQ of the first Tulip is different on Qube and RaQ - * hardware except for the weird first RaQ bringup board, - * see above for details. -DaveM - */ - if (! raq_p) { - /* All Qube's route this the same way. */ - pcibios_write_config_byte(0, 0x07<<3, PCI_INTERRUPT_LINE, - COBALT_ETHERNET_IRQ); - } else { -#ifndef RAQ_BOARD_1_WITH_HWHACKS - pcibios_write_config_byte(0, (0x07<<3), PCI_INTERRUPT_LINE, 4); -#else - pcibios_write_config_byte(0, (0x07<<3), PCI_INTERRUPT_LINE, 13); -#endif - } - - if (! raq_p) { - /* See if there is a device in the expansion slot, if so - * fixup IRQ, fix base addresses, and enable master + - * I/O + memory accesses in config space. - */ - pcibios_read_config_dword(0, 0x0a<<3, PCI_VENDOR_ID, &tmp); - if(tmp != 0xffffffff && tmp != 0x00000000) - qube_expansion_slot_fixup(); - } else { - /* If this is a RAQ, we may need to setup the second Tulip - * and SCSI as well. Due to the different configurations - * a RaQ can have, we need to explicitly check for the - * presence of each of these (optional) devices. -DaveM - */ - pcibios_read_config_dword(0, 0x0c<<3, PCI_VENDOR_ID, &tmp); - if(tmp != 0xffffffff && tmp != 0x00000000) - qube_raq_tulip_fixup(); - - pcibios_read_config_dword(0, 0x08<<3, PCI_VENDOR_ID, &tmp); - if(tmp != 0xffffffff && tmp != 0x00000000) - qube_raq_scsi_fixup(); - - /* And if we are a 2800 we have to setup the expansion slot - * too. - */ - pcibios_read_config_dword(0, 0x0a<<3, PCI_VENDOR_ID, &tmp); - if(tmp != 0xffffffff && tmp != 0x00000000) - qube_expansion_slot_fixup(); - } - - return mem_start; -} - -static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev) -{ - if ((bus == 0) && ( (dev==0) || ((dev>6) && (dev <= 12))) ) - return 0; /* OK device number */ - - return -1; /* NOT ok device number */ -} - -#define PCI_CFG_DATA ((volatile unsigned long *)0xb4000cfc) -#define PCI_CFG_CTRL ((volatile unsigned long *)0xb4000cf8) - -#define PCI_CFG_SET(dev,fun,off) \ - ((*PCI_CFG_CTRL) = (0x80000000 | ((dev)<<11) | \ - ((fun)<<8) | (off))) - -static int qube_pcibios_read_config_dword (unsigned char bus, - unsigned char dev, - unsigned char offset, - unsigned int *val) -{ - unsigned char fun = dev & 0x07; - - dev >>= 3; - if (offset & 0x3) - return PCIBIOS_BAD_REGISTER_NUMBER; - if (pci_range_ck(bus, dev)) { - *val = 0xFFFFFFFF; - return PCIBIOS_DEVICE_NOT_FOUND; - } - PCI_CFG_SET(dev, fun, offset); - *val = *PCI_CFG_DATA; - return PCIBIOS_SUCCESSFUL; -} - -static int qube_pcibios_read_config_word (unsigned char bus, - unsigned char dev, - unsigned char offset, - unsigned short *val) -{ - unsigned char fun = dev & 0x07; - - dev >>= 3; - if (offset & 0x1) - return PCIBIOS_BAD_REGISTER_NUMBER; - if (pci_range_ck(bus, dev)) { - *val = 0xffff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - PCI_CFG_SET(dev, fun, (offset & ~0x3)); - *val = *PCI_CFG_DATA >> ((offset & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int qube_pcibios_read_config_byte (unsigned char bus, - unsigned char dev, - unsigned char offset, - unsigned char *val) -{ - unsigned char fun = dev & 0x07; - - dev >>= 3; - if (pci_range_ck(bus, dev)) { - *val = 0xff; - return PCIBIOS_DEVICE_NOT_FOUND; - } - PCI_CFG_SET(dev, fun, (offset & ~0x3)); - *val = *PCI_CFG_DATA >> ((offset & 3) * 8); - return PCIBIOS_SUCCESSFUL; -} - -static int qube_pcibios_write_config_dword (unsigned char bus, - unsigned char dev, - unsigned char offset, - unsigned int val) -{ - unsigned char fun = dev & 0x07; - - dev >>= 3; - if(offset & 0x3) - return PCIBIOS_BAD_REGISTER_NUMBER; - if (pci_range_ck(bus, dev)) - return PCIBIOS_DEVICE_NOT_FOUND; - PCI_CFG_SET(dev, fun, offset); - *PCI_CFG_DATA = val; - return PCIBIOS_SUCCESSFUL; -} - -static int -qube_pcibios_write_config_word (unsigned char bus, unsigned char dev, - unsigned char offset, unsigned short val) -{ - unsigned char fun = dev & 0x07; - unsigned long tmp; - - dev >>= 3; - if (offset & 0x1) - return PCIBIOS_BAD_REGISTER_NUMBER; - if (pci_range_ck(bus, dev)) - return PCIBIOS_DEVICE_NOT_FOUND; - PCI_CFG_SET(dev, fun, (offset & ~0x3)); - tmp = *PCI_CFG_DATA; - tmp &= ~(0xffff << ((offset & 0x3) * 8)); - tmp |= (val << ((offset & 0x3) * 8)); - *PCI_CFG_DATA = tmp; - return PCIBIOS_SUCCESSFUL; -} - -static int -qube_pcibios_write_config_byte (unsigned char bus, unsigned char dev, - unsigned char offset, unsigned char val) -{ - unsigned char fun = dev & 0x07; - unsigned long tmp; - - dev >>= 3; - if (pci_range_ck(bus, dev)) - return PCIBIOS_DEVICE_NOT_FOUND; - PCI_CFG_SET(dev, fun, (offset & ~0x3)); - tmp = *PCI_CFG_DATA; - tmp &= ~(0xff << ((offset & 0x3) * 8)); - tmp |= (val << ((offset & 0x3) * 8)); - *PCI_CFG_DATA = tmp; - return PCIBIOS_SUCCESSFUL; -} - -struct pci_ops qube_pci_ops = { - qube_pcibios_fixup, - qube_pcibios_read_config_byte, - qube_pcibios_read_config_word, - qube_pcibios_read_config_dword, - qube_pcibios_write_config_byte, - qube_pcibios_write_config_word, - qube_pcibios_write_config_dword -}; - -#endif /* CONFIG_PCI */ diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/reset.c linux/arch/mips/cobalt/reset.c --- v2.4.1/linux/arch/mips/cobalt/reset.c Thu Jul 13 09:39:49 2000 +++ linux/arch/mips/cobalt/reset.c Wed Dec 31 16:00:00 1969 @@ -1,61 +0,0 @@ -/* - * Reset a Cobalt Qube. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -void cobalt_machine_restart(char *command) -{ - *(volatile char *)0xbc000000 = 0x0f; - - /* - * Ouch, we're still alive ... This time we take the silver bullet ... - * ... and find that we leave the hardware in a state in which the - * kernel in the flush locks up somewhen during of after the PCI - * detection stuff. - */ - set_cp0_status((ST0_BEV | ST0_ERL), (ST0_BEV | ST0_ERL)); - set_cp0_config(CONFIG_CM_CMASK, CONFIG_CM_UNCACHED); - flush_cache_all(); - write_32bit_cp0_register(CP0_WIRED, 0); - __asm__ __volatile__( - "jr\t%0" - : - : "r" (0xbfc00000)); -} - -extern int led_state; -#define kLED 0xBC000000 -#define LEDSet(x) (*(volatile unsigned char *) kLED) = (( unsigned char)x) - -void cobalt_machine_halt(void) -{ - int mark; - - // Blink our cute little LED (number 3)... - while (1) { - led_state = led_state | ( 1 << 3 ); - LEDSet(led_state); - mark = jiffies; - while (jiffies<(mark+HZ)); - led_state = led_state & ~( 1 << 3 ); - LEDSet(led_state); - mark = jiffies; - while (jiffies<(mark+HZ)); - } -} - -/* - * This triggers the luser mode device driver for the power switch ;-) - */ -void cobalt_machine_power_off(void) -{ - printk("You can switch the machine off now.\n"); - cobalt_machine_halt(); -} diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/serial.h linux/arch/mips/cobalt/serial.h --- v2.4.1/linux/arch/mips/cobalt/serial.h Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/cobalt/serial.h Wed Dec 31 16:00:00 1969 @@ -1,28 +0,0 @@ -/* - * - * Filename: serial.h - * - * Description: Some general definitions used for serial code - * - * Author(s): Timothy Stonis - * - * Copyright 1997, Cobalt Microserver, Inc. - */ - -/* - * Serial port definitions - */ -#define kSCC_Base kGal_DevBank1Base -#define kHelloWorldMsg "Cobalt Networks Diagnostics - 'We serve it, you surf it'\n\r" -#define kSCC_ChanA 0x01 -#define kSCC_ChanB 0x00 -#define kSCC_Direct 0x02 -#define kSCC_Command 0x00 - -#define kSCC_TestVal 0xA5 -#define kSCC_19200 0x07 /* x32 clock mode, 19200 baud */ -#define kSCC_115200 0x01 /* x16 clock mode, 115200 baud */ - -#define Read8530(n) (*((unsigned char *) (kSCC_Base | (n)))) - -#define Write8530(x,y) (*((unsigned char *) (kSCC_Base | (x))) = (y)) diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/setup.c linux/arch/mips/cobalt/setup.c --- v2.4.1/linux/arch/mips/cobalt/setup.c Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/cobalt/setup.c Wed Dec 31 16:00:00 1969 @@ -1,411 +0,0 @@ -/* - * Setup pointers to hardware dependand routines. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1996, 1997 by Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void cobalt_machine_restart(char *command); -extern void cobalt_machine_halt(void); -extern void cobalt_machine_power_off(void); - -extern int serial_console; - -/* - * Initial irq handlers. - */ -static void no_action(int cpl, void *dev_id, struct pt_regs *regs) -{ -} - -/* - * IRQ2 is cascade interrupt to second interrupt controller - */ -static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; - -extern struct feature cobalt_feature; -extern asmlinkage void cobalt_handle_int(void); - -static void cobalt_irq_setup(void) -{ - /* - * Clear all of the interrupts while we change the able around a bit. - */ - set_cp0_status(ST0_IM, 0); - - /* Sets the exception_handler array. */ - set_except_vector(0, cobalt_handle_int); - - request_region(0xb0000020, 0x20, "pic1"); - request_region(0xb00000A0, 0x20, "pic2"); - setup_x86_irq(2, &irq2); - - cli(); - - set_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1 | IE_IRQ0); - - /* Setup VIA irq mask */ - VIA_PORT_WRITE(0x20, 0x10); - VIA_PORT_WRITE(0x21, 0x00); - VIA_PORT_WRITE(0x21, 0x00); - - VIA_PORT_WRITE(0xa0, 0x10); - VIA_PORT_WRITE(0xa1, 0x00); - VIA_PORT_WRITE(0xa1, 0x00); -} - -void (*board_time_init)(struct irqaction *irq); - -static void cobalt_calibrate_timer(void) -{ - volatile unsigned long *timer_reg = (volatile unsigned long *)0xb4000850; - - /* Default to 150MHZ, since this is what we are shipping. */ - *timer_reg = 500000; -} - -static void cobalt_time_init(struct irqaction *irq) -{ - /* Load timer value for 100 Hz */ - cobalt_calibrate_timer(); - /* *((volatile unsigned long *) 0xb4000850) = (unsigned long) 440000; */ - - setup_x86_irq(0, irq); - - /* Enable timer ints */ - *((volatile unsigned long *) 0xb4000864) = (unsigned long) 0x00000003; - /* Unmask timer int */ - *((volatile unsigned long *) 0xb4000c1c) = (unsigned long) 0x00000100; -} - -extern struct pci_ops qube_pci_ops; -int cobalt_serial_present; -int cobalt_serial_type; -int cobalt_is_raq; - -void cobalt_setup(void) -{ - tag *atag; - - /* - * We just check if a tag_screen_info can be gathered - * in setup_arch(), if yes we don't proceed futher... - */ - atag = bi_TagFind(tag_screen_info); - if (!atag) { - /* - * If no, we try to find the tag_arc_displayinfo which is - * always created by Milo for an ARC box (for now Milo only - * works on ARC boxes :) -Stoned. - */ - atag = bi_TagFind(tag_arcdisplayinfo); - if (atag) { - - screen_info.orig_x = - ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x; - screen_info.orig_y = - ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y; - screen_info.orig_video_cols = - ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns; - screen_info.orig_video_lines = - ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines; - } - } - - _machine_restart = cobalt_machine_restart; - _machine_halt = cobalt_machine_halt; - _machine_power_off = cobalt_machine_power_off; - - irq_setup = cobalt_irq_setup; - board_time_init = cobalt_time_init; - feature = &cobalt_feature; - mips_io_port_base = COBALT_LOCAL_IO_SPACE; - - pci_ops = &qube_pci_ops; - -#ifdef CONFIG_COBALT_SERIAL - serial_console = 1; -#endif /* CONFIG_COBALT_SERIAL */ - - /* We have to do this early, here, before the value could - * possibly be overwritten by the bootup sequence. - */ - cobalt_serial_present = *((unsigned long *) 0xa020001c); - cobalt_serial_type = *((unsigned long *) 0xa0200020); - cobalt_is_raq = (cobalt_serial_present != 0x0 - && cobalt_serial_type == 0x1); -} - -void AddTagsEndSymbol(void); -int bi_TagAdd (enum bi_tag type, unsigned long size, void *data); -unsigned long next_tag = (unsigned long) NULL; -unsigned long memory_upper = (unsigned long) NULL; - -int bi_TagAdd (enum bi_tag type, unsigned long size, void *data) -{ - tag t; - unsigned long addr; - - t.tag = type; - t.size = size; - - /* - * If next_tag equals NULL it means it's the first tag we're asked - * to create. - */ - if (next_tag == (unsigned long) NULL) { - /* - * If memory_upper not equals NULL it means that identify() - * was able to figure out how much memory is present in the - * box so we initialize next_tag from it. - */ - if (memory_upper != (unsigned long) NULL) - next_tag = memory_upper; - - /* Else we rely on the fact that the first tag we create for - * a box for which we don't know how RAM it gots is a tag of - * type tag_memupper. This is ensured by the first entry in - * the defaults tag list for such a box (see identify.c). - * First we check this. - */ - else { - /* Ok it's a memupper tag: we put it's value in - * memory_upper so launch() can pass it to the - * kernel in register a0 and we initialize next_tag. - */ - next_tag = *(unsigned long *) data; - memory_upper = *((unsigned long *) data); - } - } - - /* We put the tag structure. */ - addr = next_tag - (sizeof (tag)); - - memcpy ((void *) addr, (void *) &t, (size_t) (sizeof (tag))); - - /* We put the tag's data if any. */ - if (size != 0) { - addr = addr - size; - memcpy ((void *) addr, data, (size_t) (t.size)); - } - - /* - * Set next_tag ready for the next tag creation. - */ - next_tag = addr; - AddTagsEndSymbol(); - - return 0; -} - -void SetUpBootInfo(void) -{ - unsigned long LongVar; - int atag; - - /* - * This is hard coded here but will change when we have a - * Size mem routine. - */ - - /* - * 64mb of memory. - */ - - //mips_memory_upper = 0x84000000; - - -#ifndef BOOTLOADER - -#if 0 /* You break'a the kernel I break'a ya face. -DaveM */ - - /* Eight meg of memory. */ - mips_memory_upper = 0x80800000; /* XXX this appears to be unused - - this assignment is not present in the normal - $cvstree/linux/arch/mips/cobalt/setup.c */ -#endif -#else -#include "../../../../include/diagdefs.h" - mips_memory_upper = (unsigned long) kBootloaderMipsMemoryUpper; -#endif - - LongVar = mips_memory_upper; - atag = bi_TagAdd(tag_memupper, ULONGSIZE, &LongVar); - - /* Here is the machine type. - */ - LongVar = MACH_COBALT_27; - atag = bi_TagAdd(tag_machtype, ULONGSIZE, &LongVar); - - LongVar = 0x80000000; - atag = bi_TagAdd(tag_memlower, ULONGSIZE, &LongVar); - - LongVar = CPU_R4300; - atag = bi_TagAdd(tag_cputype, ULONGSIZE, &LongVar); - - LongVar = MACH_GROUP_COBALT; - atag = bi_TagAdd(tag_machgroup, ULONGSIZE, &LongVar); - - LongVar = 0; - atag = bi_TagAdd(tag_scache_size, ULONGSIZE, &LongVar); - - LongVar = 48; - atag = bi_TagAdd(tag_tlb_entries, ULONGSIZE, &LongVar); - - LongVar = 0; - atag = bi_TagAdd(tag_drive_info, ULONGSIZE, &LongVar); - - LongVar = 0xe0800000; - atag = bi_TagAdd(tag_vram_base, ULONGSIZE, &LongVar); - - LongVar = 0; - atag = bi_TagAdd(tag_dummy, 0, &LongVar); -} - -void AddTagsEndSymbol(void) -{ - short X; - X = 1; -} - -/* - * Oh shit, this is so crappy ... - */ -#include -#include -int my_cacheflush(unsigned long start, unsigned long size, unsigned int what) -{ - flush_cache_range(current->mm, start, start + size); - return 0; -} - - -/* - * The ROM set the flag to 0x1 to turn off output. This is interpreted - * as "valid", "no kernel output", and index '0' into the following - * tables. We overload entry '0' to specify a sensible default rate. - */ -static int cons_baud_int[] = { 9600, 0, 9600, 0, 0, 115200, 0, 0 }; -static int cons_baud_baud[] = { B9600, 0, B9600, 0, 0, B115200, 0, 0 }; - -static union cobalt_cons_info -cobalt_get_console_info(void) -{ - char board_id = 0; - static union cobalt_cons_info cons_info; - static int read_info = 0; - extern void add_init_env(char *); - - if (read_info) - return cons_info; - - VIA_PORT_WRITE(VIA_CMOS_ADDR, VIA_CMOS_CONSOLE_FLG); - cons_info.ccons_char = VIA_PORT_READ(VIA_CMOS_DATA); - -#if 0 - printk("cobalt_get_console_info: read 0x%x from console flag\n", - cons_info.ccons_char); -#endif - - /* - * CMOS hasn't been initialized or baud rate isn't known. - * - read the board id and provide backwards compat. - */ - if (cons_info.ccons_bits.valid != VIA_CMOS_CONS_VALID - || ! cons_baud_int[cons_info.ccons_bits.baud] - || ! cons_baud_baud[cons_info.ccons_bits.baud]) { - pcibios_read_config_byte(0, PCI_DEVSHFT(COBALT_PCICONF_VIA), - VIA_COBALT_BRD_ID_REG, &board_id); - -#if 0 - printk("cobalt_get_console_info: read 0x%x from board config\n", - board_id); -#endif - - switch (VIA_COBALT_BRD_REG_to_ID(board_id)) { - case COBALT_BRD_ID_QUBE1: - cons_info.ccons_bits.baud = VIA_CMOS_CONS_115K; - cons_info.ccons_bits.kout = 1; - break; - case COBALT_BRD_ID_RAQ1: - cons_info.ccons_bits.baud = VIA_CMOS_CONS_9600; - cons_info.ccons_bits.kout = 1; - break; - case COBALT_BRD_ID_QUBE2: - cons_info.ccons_bits.baud = VIA_CMOS_CONS_9600; - cons_info.ccons_bits.kout = 0; - break; - case COBALT_BRD_ID_RAQ2: - cons_info.ccons_bits.baud = VIA_CMOS_CONS_9600; - cons_info.ccons_bits.kout = 1; - break; - } - cons_info.ccons_bits.valid = VIA_CMOS_CONS_VALID; - } - - read_info = 1; - -#if defined(DEBUG_LOADER) - cons_info.ccons_bits.kout = 1; -#endif - - if (!cons_info.ccons_bits.kout) { - add_init_env("CONSOLE=/dev/null"); - } - -#if 0 - printk("cobalt_get_console_info: returning 0x%x\n", - cons_info.ccons_char); -#endif - - return cons_info; -} - -int -cobalt_cons_koutok(void) -{ - union cobalt_cons_info cons; - - cons = cobalt_get_console_info(); - - return cons.ccons_bits.kout; -} - -int -cobalt_cons_baudbaud(void) -{ - union cobalt_cons_info cons; - - cons = cobalt_get_console_info(); - - return cons_baud_baud[cons.ccons_bits.baud]; -} - -int -cobalt_cons_baudint(void) -{ - union cobalt_cons_info cons; - - cons = cobalt_get_console_info(); - - return cons_baud_int[cons.ccons_bits.baud]; -} diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/via.c linux/arch/mips/cobalt/via.c --- v2.4.1/linux/arch/mips/cobalt/via.c Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/cobalt/via.c Wed Dec 31 16:00:00 1969 @@ -1,90 +0,0 @@ -/* - * Interrupt handling for the VIA ISA bridge. - * - * Everything the same ... just different ... - */ -#include -#include -#include -#include - -extern asmlinkage void do_IRQ(int irq, struct pt_regs * regs); - -extern unsigned char cache_21; -extern unsigned char cache_A1; - -/* - * (un)mask_irq, disable_irq() and enable_irq() only handle (E)ISA and - * PCI devices. Other onboard hardware needs specific routines. - */ -void mask_irq(unsigned int irq_nr) -{ - unsigned char mask; - - mask = 1 << (irq_nr & 7); - if (irq_nr < 8) { - cache_21 |= mask; - outb(cache_21, 0x10000021); - } else { - cache_A1 |= mask; - outb(cache_A1, 0x100000a1); - } -} - -void unmask_irq(unsigned int irq_nr) -{ - unsigned char mask; - - mask = ~(1 << (irq_nr & 7)); - if (irq_nr < 8) { - cache_21 &= mask; - outb(cache_21, 0x10000021); - } else { - cache_A1 &= mask; - outb(cache_A1, 0x100000a1); - } -} - -asmlinkage void via_irq(struct pt_regs *regs) -{ - char mstat, sstat; - - /* Read Master Status */ - VIA_PORT_WRITE(0x20, 0x0C); - mstat = VIA_PORT_READ(0x20); - - if (mstat < 0) { - mstat &= 0x7f; - if (mstat != 2) { - do_IRQ(mstat, regs); - VIA_PORT_WRITE(0x20, mstat | 0x20); - } else { - sstat = VIA_PORT_READ(0xA0); - - /* Slave interrupt */ - VIA_PORT_WRITE(0xA0, 0x0C); - sstat = VIA_PORT_READ(0xA0); - - if (sstat < 0) { - do_IRQ((sstat + 8) & 0x7f, regs); - VIA_PORT_WRITE(0x20, 0x22); - VIA_PORT_WRITE(0xA0, (sstat & 0x7f) | 0x20); - } else { - printk("Spurious slave interrupt...\n"); - } - } - } else - printk("Spurious master interrupt..."); -} - -asmlinkage void galileo_irq(struct pt_regs *regs) -{ - unsigned long irq_src = *((unsigned long *) 0xb4000c18); - - /* Check for timer irq ... */ - if (irq_src & 0x00000100) { - *((volatile unsigned long *) 0xb4000c18) = 0; - do_IRQ(0, regs); - } else - printk("Spurious Galileo interrupt...\n"); -} diff -u --recursive --new-file v2.4.1/linux/arch/mips/cobalt/z8530.h linux/arch/mips/cobalt/z8530.h --- v2.4.1/linux/arch/mips/cobalt/z8530.h Sun Jul 9 22:18:15 2000 +++ linux/arch/mips/cobalt/z8530.h Wed Dec 31 16:00:00 1969 @@ -1,219 +0,0 @@ -/* 8530 Serial Communications Controller Register definitions */ -#define FLAG 0x7e - -/* Write Register 0 */ -#define R0 0 /* Register selects */ -#define R1 1 -#define R2 2 -#define R3 3 -#define R4 4 -#define R5 5 -#define R6 6 -#define R7 7 -#define R8 8 -#define R9 9 -#define R10 10 -#define R11 11 -#define R12 12 -#define R13 13 -#define R14 14 -#define R15 15 - -#define NULLCODE 0 /* Null Code */ -#define POINT_HIGH 0x8 /* Select upper half of registers */ -#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ -#define SEND_ABORT 0x18 /* HDLC Abort */ -#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ -#define RES_Tx_P 0x28 /* Reset TxINT Pending */ -#define ERR_RES 0x30 /* Error Reset */ -#define RES_H_IUS 0x38 /* Reset highest IUS */ - -#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ -#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ -#define RES_EOM_L 0xC0 /* Reset EOM latch */ - -/* Write Register 1 */ - -#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ -#define TxINT_ENAB 0x2 /* Tx Int Enable */ -#define PAR_SPEC 0x4 /* Parity is special condition */ - -#define RxINT_DISAB 0 /* Rx Int Disable */ -#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ -#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ -#define INT_ERR_Rx 0x18 /* Int on error only */ - -#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ -#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ -#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ - -/* Write Register #2 (Interrupt Vector) */ - -/* Write Register 3 */ - -#define RxENABLE 0x1 /* Rx Enable */ -#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ -#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ -#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ -#define ENT_HM 0x10 /* Enter Hunt Mode */ -#define AUTO_ENAB 0x20 /* Auto Enables */ -#define Rx5 0x0 /* Rx 5 Bits/Character */ -#define Rx7 0x40 /* Rx 7 Bits/Character */ -#define Rx6 0x80 /* Rx 6 Bits/Character */ -#define Rx8 0xc0 /* Rx 8 Bits/Character */ - -/* Write Register 4 */ - -#define PAR_ENA 0x1 /* Parity Enable */ -#define PAR_EVEN 0x2 /* Parity Even/Odd* */ - -#define SYNC_ENAB 0 /* Sync Modes Enable */ -#define SB1 0x4 /* 1 stop bit/char */ -#define SB15 0x8 /* 1.5 stop bits/char */ -#define SB2 0xc /* 2 stop bits/char */ - -#define MONSYNC 0 /* 8 Bit Sync character */ -#define BISYNC 0x10 /* 16 bit sync character */ -#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ -#define EXTSYNC 0x30 /* External Sync Mode */ - -#define X1CLK 0x0 /* x1 clock mode */ -#define X16CLK 0x40 /* x16 clock mode */ -#define X32CLK 0x80 /* x32 clock mode */ -#define X64CLK 0xC0 /* x64 clock mode */ - -/* Write Register 5 */ - -#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ -#define RTS 0x2 /* RTS */ -#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ -#define TxENAB 0x8 /* Tx Enable */ -#define SND_BRK 0x10 /* Send Break */ -#define Tx5 0x0 /* Tx 5 bits (or less)/character */ -#define Tx7 0x20 /* Tx 7 bits/character */ -#define Tx6 0x40 /* Tx 6 bits/character */ -#define Tx8 0x60 /* Tx 8 bits/character */ -#define DTR 0x80 /* DTR */ - -/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ - -/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ - -/* Write Register 8 (transmit buffer) */ - -/* Write Register 9 (Master interrupt control) */ -#define VIS 1 /* Vector Includes Status */ -#define NV 2 /* No Vector */ -#define DLC 4 /* Disable Lower Chain */ -#define MIE 8 /* Master Interrupt Enable */ -#define STATHI 0x10 /* Status high */ -#define NORESET 0 /* No reset on write to R9 */ -#define CHRB 0x40 /* Reset channel B */ -#define CHRA 0x80 /* Reset channel A */ -#define FHWRES 0xc0 /* Force hardware reset */ - -/* Write Register 10 (misc control bits) */ -#define BIT6 1 /* 6 bit/8bit sync */ -#define LOOPMODE 2 /* SDLC Loop mode */ -#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ -#define MARKIDLE 8 /* Mark/flag on idle */ -#define GAOP 0x10 /* Go active on poll */ -#define NRZ 0 /* NRZ mode */ -#define NRZI 0x20 /* NRZI mode */ -#define FM1 0x40 /* FM1 (transition = 1) */ -#define FM0 0x60 /* FM0 (transition = 0) */ -#define CRCPS 0x80 /* CRC Preset I/O */ - -/* Write Register 11 (Clock Mode control) */ -#define TRxCXT 0 /* TRxC = Xtal output */ -#define TRxCTC 1 /* TRxC = Transmit clock */ -#define TRxCBR 2 /* TRxC = BR Generator Output */ -#define TRxCDP 3 /* TRxC = DPLL output */ -#define TRxCOI 4 /* TRxC O/I */ -#define TCRTxCP 0 /* Transmit clock = RTxC pin */ -#define TCTRxCP 8 /* Transmit clock = TRxC pin */ -#define TCBR 0x10 /* Transmit clock = BR Generator output */ -#define TCDPLL 0x18 /* Transmit clock = DPLL output */ -#define RCRTxCP 0 /* Receive clock = RTxC pin */ -#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ -#define RCBR 0x40 /* Receive clock = BR Generator output */ -#define RCDPLL 0x60 /* Receive clock = DPLL output */ -#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ - -/* Write Register 12 (lower byte of baud rate generator time constant) */ - -/* Write Register 13 (upper byte of baud rate generator time constant) */ - -/* Write Register 14 (Misc control bits) */ -#define BRENABL 1 /* Baud rate generator enable */ -#define BRSRC 2 /* Baud rate generator source */ -#define DTRREQ 4 /* DTR/Request function */ -#define AUTOECHO 8 /* Auto Echo */ -#define LOOPBAK 0x10 /* Local loopback */ -#define SEARCH 0x20 /* Enter search mode */ -#define RMC 0x40 /* Reset missing clock */ -#define DISDPLL 0x60 /* Disable DPLL */ -#define SSBR 0x80 /* Set DPLL source = BR generator */ -#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ -#define SFMM 0xc0 /* Set FM mode */ -#define SNRZI 0xe0 /* Set NRZI mode */ - -/* Write Register 15 (external/status interrupt control) */ -#define ZCIE 2 /* Zero count IE */ -#define DCDIE 8 /* DCD IE */ -#define SYNCIE 0x10 /* Sync/hunt IE */ -#define CTSIE 0x20 /* CTS IE */ -#define TxUIE 0x40 /* Tx Underrun/EOM IE */ -#define BRKIE 0x80 /* Break/Abort IE */ - - -/* Read Register 0 */ -#define Rx_CH_AV 0x1 /* Rx Character Available */ -#define ZCOUNT 0x2 /* Zero count */ -#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ -#define DCD 0x8 /* DCD */ -#define SYNC_HUNT 0x10 /* Sync/hunt */ -#define CTS 0x20 /* CTS */ -#define TxEOM 0x40 /* Tx underrun */ -#define BRK_ABRT 0x80 /* Break/Abort */ - -/* Read Register 1 */ -#define ALL_SNT 0x1 /* All sent */ -/* Residue Data for 8 Rx bits/char programmed */ -#define RES3 0x8 /* 0/3 */ -#define RES4 0x4 /* 0/4 */ -#define RES5 0xc /* 0/5 */ -#define RES6 0x2 /* 0/6 */ -#define RES7 0xa /* 0/7 */ -#define RES8 0x6 /* 0/8 */ -#define RES18 0xe /* 1/8 */ -#define RES28 0x0 /* 2/8 */ -/* Special Rx Condition Interrupts */ -#define PAR_ERR 0x10 /* Parity error */ -#define Rx_OVR 0x20 /* Rx Overrun Error */ -#define CRC_ERR 0x40 /* CRC/Framing Error */ -#define END_FR 0x80 /* End of Frame (SDLC) */ - -/* Read Register 2 (channel b only) - Interrupt vector */ - -/* Read Register 3 (interrupt pending register) ch a only */ -#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ -#define CHBTxIP 0x2 /* Channel B Tx IP */ -#define CHBRxIP 0x4 /* Channel B Rx IP */ -#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ -#define CHATxIP 0x10 /* Channel A Tx IP */ -#define CHARxIP 0x20 /* Channel A Rx IP */ - -/* Read Register 8 (receive data register) */ - -/* Read Register 10 (misc status bits) */ -#define ONLOOP 2 /* On loop */ -#define LOOPSEND 0x10 /* Loop sending */ -#define CLK2MIS 0x40 /* Two clocks missing */ -#define CLK1MIS 0x80 /* One clock missing */ - -/* Read Register 12 (lower byte of baud rate generator constant) */ - -/* Read Register 13 (upper byte of baud rate generator constant) */ - -/* Read Register 15 (value of WR 15) */ diff -u --recursive --new-file v2.4.1/linux/arch/mips/dec/irq.c linux/arch/mips/dec/irq.c --- v2.4.1/linux/arch/mips/dec/irq.c Fri Aug 4 16:15:37 2000 +++ linux/arch/mips/dec/irq.c Fri Feb 9 11:29:44 2001 @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c --- v2.4.1/linux/arch/mips/kernel/irixelf.c Sun Sep 3 11:49:25 2000 +++ linux/arch/mips/kernel/irixelf.c Fri Feb 9 11:29:44 2001 @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c --- v2.4.1/linux/arch/mips/kernel/irq.c Fri Aug 4 16:15:37 2000 +++ linux/arch/mips/kernel/irq.c Fri Feb 9 11:29:44 2001 @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c --- v2.4.1/linux/arch/mips/kernel/process.c Tue Sep 5 13:50:02 2000 +++ linux/arch/mips/kernel/process.c Fri Feb 9 11:29:44 2001 @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c --- v2.4.1/linux/arch/mips/kernel/setup.c Tue Jul 11 11:14:48 2000 +++ linux/arch/mips/kernel/setup.c Fri Feb 9 11:29:44 2001 @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c --- v2.4.1/linux/arch/mips/kernel/sysirix.c Sat Aug 12 19:48:04 2000 +++ linux/arch/mips/kernel/sysirix.c Fri Feb 9 11:29:44 2001 @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/orion/irq.c linux/arch/mips/orion/irq.c --- v2.4.1/linux/arch/mips/orion/irq.c Fri Aug 4 16:15:38 2000 +++ linux/arch/mips/orion/irq.c Fri Feb 9 11:29:44 2001 @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/orion/misc.c linux/arch/mips/orion/misc.c --- v2.4.1/linux/arch/mips/orion/misc.c Fri Aug 4 18:31:19 2000 +++ linux/arch/mips/orion/misc.c Fri Feb 9 11:29:44 2001 @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/orion/setup.c linux/arch/mips/orion/setup.c --- v2.4.1/linux/arch/mips/orion/setup.c Fri Aug 4 18:31:19 2000 +++ linux/arch/mips/orion/setup.c Fri Feb 9 11:29:44 2001 @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips/sgi/kernel/indy_int.c linux/arch/mips/sgi/kernel/indy_int.c --- v2.4.1/linux/arch/mips/sgi/kernel/indy_int.c Fri Aug 4 16:15:37 2000 +++ linux/arch/mips/sgi/kernel/indy_int.c Fri Feb 9 11:29:44 2001 @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips64/Makefile linux/arch/mips64/Makefile --- v2.4.1/linux/arch/mips64/Makefile Wed Dec 6 20:32:41 2000 +++ linux/arch/mips64/Makefile Sun Feb 4 21:48:46 2001 @@ -33,7 +33,7 @@ # machines may also. Since BFD is incredibly buggy with respect to # crossformat linking we rely on the elf2ecoff tool for format conversion. # -CFLAGS += -I $(TOPDIR)/include/asm $(CFLAGS) +CFLAGS += -I $(TOPDIR)/include/asm/gcc $(CFLAGS) CFLAGS += -mabi=64 -G 0 -mno-abicalls -fno-pic -Wa,--trap -pipe LINKFLAGS += -G 0 -static # -N MODFLAGS += -mlong-calls @@ -153,7 +153,6 @@ archclean: @$(MAKEBOOT) clean - $(MAKE) -C arch/$(ARCH)/kernel clean $(MAKE) -C arch/$(ARCH)/tools clean rm -f vmlinux.64 arch/$(ARCH)/ld.script.elf32 diff -u --recursive --new-file v2.4.1/linux/arch/mips64/arc/Makefile linux/arch/mips64/arc/Makefile --- v2.4.1/linux/arch/mips64/arc/Makefile Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/arc/Makefile Sun Feb 4 21:48:46 2001 @@ -3,15 +3,13 @@ # L_TARGET = arclib.a -L_OBJS = init.o printf.o tree.o env.o cmdline.o misc.o time.o \ - file.o identify.o +obj-y := init.o printf.o tree.o env.o cmdline.o misc.o time.o file.o \ + identify.o ifndef CONFIG_SGI_IP27 -L_OBJS += console.o + obj-y += console.o endif -ifdef CONFIG_ARC_MEMORY -L_OBJS += memory.o -endif +obj-$(CONFIG_ARC_MEMORY) += memory.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/mips64/boot/Makefile linux/arch/mips64/boot/Makefile --- v2.4.1/linux/arch/mips64/boot/Makefile Sun Jul 9 22:18:16 2000 +++ linux/arch/mips64/boot/Makefile Sun Feb 4 21:48:46 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.1 1999/08/18 21:46: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 diff -u --recursive --new-file v2.4.1/linux/arch/mips64/config.in linux/arch/mips64/config.in --- v2.4.1/linux/arch/mips64/config.in Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/config.in Sun Feb 4 21:48:46 2001 @@ -1,4 +1,3 @@ -# $Id: config.in,v 1.19 2000/03/27 01:44:45 ralf Exp $ # # For a description of the syntax of this configuration file, # see Documentation/kbuild/config-language.txt. @@ -76,7 +75,7 @@ "R4300 CONFIG_CPU_R4300 \ R4x00 CONFIG_CPU_R4X00 \ R5000 CONFIG_CPU_R5000 \ - R56x0 CONFIG_CPU_NEVADA \ + R52x0 CONFIG_CPU_NEVADA \ R8000 CONFIG_CPU_R8000 \ R10000 CONFIG_CPU_R10000" R4x00 endmenu diff -u --recursive --new-file v2.4.1/linux/arch/mips64/defconfig linux/arch/mips64/defconfig --- v2.4.1/linux/arch/mips64/defconfig Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/defconfig Sun Feb 4 21:48:46 2001 @@ -91,7 +91,6 @@ # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set # CONFIG_BLK_DEV_LVM is not set -# CONFIG_LVM_PROC_FS is not set # # Networking options @@ -144,6 +143,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set @@ -350,6 +350,8 @@ # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -405,8 +407,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -426,6 +426,7 @@ CONFIG_SGI_PARTITION=y # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set CONFIG_KCORE_ELF=y diff -u --recursive --new-file v2.4.1/linux/arch/mips64/defconfig-ip22 linux/arch/mips64/defconfig-ip22 --- v2.4.1/linux/arch/mips64/defconfig-ip22 Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/defconfig-ip22 Sun Feb 4 21:48:46 2001 @@ -81,7 +81,6 @@ # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set # CONFIG_BLK_DEV_LVM is not set -# CONFIG_LVM_PROC_FS is not set # # Networking options @@ -267,6 +266,8 @@ # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -321,8 +322,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -331,6 +330,7 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_SGI_PARTITION=y +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set # diff -u --recursive --new-file v2.4.1/linux/arch/mips64/defconfig-ip27 linux/arch/mips64/defconfig-ip27 --- v2.4.1/linux/arch/mips64/defconfig-ip27 Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/defconfig-ip27 Sun Feb 4 21:48:46 2001 @@ -91,7 +91,6 @@ # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set # CONFIG_BLK_DEV_LVM is not set -# CONFIG_LVM_PROC_FS is not set # # Networking options @@ -144,6 +143,7 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set # CONFIG_BLK_DEV_SR is not set # CONFIG_CHR_DEV_SG is not set @@ -350,6 +350,8 @@ # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y # CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set @@ -405,8 +407,6 @@ # CONFIG_NCPFS_NFS_NS is not set # CONFIG_NCPFS_OS2_NS is not set # CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_MOUNT_SUBDIR is not set -# CONFIG_NCPFS_NDS_DOMAINS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set @@ -426,6 +426,7 @@ CONFIG_SGI_PARTITION=y # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_SMB_NLS is not set # CONFIG_NLS is not set CONFIG_KCORE_ELF=y diff -u --recursive --new-file v2.4.1/linux/arch/mips64/kernel/Makefile linux/arch/mips64/kernel/Makefile --- v2.4.1/linux/arch/mips64/kernel/Makefile Sun Jul 9 22:18:16 2000 +++ linux/arch/mips64/kernel/Makefile Sun Feb 4 21:48:46 2001 @@ -12,27 +12,20 @@ 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 \ + +export-objs = mips64_ksyms.o + +obj-y := branch.o entry.o proc.o process.o ptrace.o r4k_cache.o r4k_fpu.o \ r4k_genex.o r4k_switch.o r4k_tlb.o r4k_tlb_debug.o r4k_tlb_glue.o \ scall_64.o semaphore.o setup.o signal.o softfp.o syscall.o \ traps.o unaligned.o -OX_OBJS := mips64_ksyms.o - -ifdef CONFIG_MIPS32_COMPAT -O_OBJS += linux32.o scall_o32.o signal32.o ioctl32.o -endif -ifdef CONFIG_BINFMT_ELF32 -O_OBJS += binfmt_elf32.o -endif - -ifdef CONFIG_SMP -O_OBJS += smp.o -endif +obj-$(CONFIG_MODULES) += mips64_ksyms.o +obj-$(CONFIG_MIPS32_COMPAT) += linux32.o scall_o32.o signal32.o ioctl32.o +obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o +obj-$(CONFIG_SMP) += smp.o CFLAGS_r4k_genex.o := -P CFLAGS_r4k_tlb_glue.o := -P - -clean: include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/mips64/kernel/process.c linux/arch/mips64/kernel/process.c --- v2.4.1/linux/arch/mips64/kernel/process.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/kernel/process.c Fri Feb 9 11:29:44 2001 @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips64/kernel/setup.c linux/arch/mips64/kernel/setup.c --- v2.4.1/linux/arch/mips64/kernel/setup.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/kernel/setup.c Fri Feb 9 11:29:44 2001 @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -55,6 +55,8 @@ * Do we have a cyclecounter available? */ char cyclecounter_available; + +unsigned long loops_per_sec; /* * Set if box has EISA slots. diff -u --recursive --new-file v2.4.1/linux/arch/mips64/kernel/smp.c linux/arch/mips64/kernel/smp.c --- v2.4.1/linux/arch/mips64/kernel/smp.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/kernel/smp.c Sun Feb 4 21:48:46 2001 @@ -57,7 +57,7 @@ int smp_threads_ready; /* Not used */ atomic_t smp_commenced = ATOMIC_INIT(0); struct cpuinfo_mips cpu_data[NR_CPUS]; -int smp_num_cpus; /* Number that came online. */ +int smp_num_cpus = 1; /* Number that came online. */ int __cpu_number_map[NR_CPUS]; int __cpu_logical_map[NR_CPUS]; cycles_t cacheflush_time; diff -u --recursive --new-file v2.4.1/linux/arch/mips64/lib/Makefile linux/arch/mips64/lib/Makefile --- v2.4.1/linux/arch/mips64/lib/Makefile Tue Dec 5 23:15:12 2000 +++ linux/arch/mips64/lib/Makefile Sun Feb 4 21:48:46 2001 @@ -8,7 +8,8 @@ $(CC) $(CFLAGS) -c $< -o $*.o L_TARGET = lib.a -L_OBJS = csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \ + +obj-y += csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \ floppy-no.o ide-std.o ide-no.o kbd-std.o kbd-no.o rtc-std.o \ rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o \ strnlen_user.o watch.o diff -u --recursive --new-file v2.4.1/linux/arch/mips64/lib/rtc-no.c linux/arch/mips64/lib/rtc-no.c --- v2.4.1/linux/arch/mips64/lib/rtc-no.c Sat May 13 08:30:17 2000 +++ linux/arch/mips64/lib/rtc-no.c Sun Feb 4 21:48:46 2001 @@ -1,5 +1,4 @@ -/* $Id: rtc-no.c,v 1.1 1999/08/21 21:43:01 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -7,9 +6,10 @@ * Stub RTC routines to keep Linux from crashing on machine which don't * have a RTC chip. * - * Copyright (C) 1998 by Ralf Baechle + * Copyright (C) 1998, 2001 by Ralf Baechle */ #include +#include #include static unsigned char no_rtc_read_data(unsigned long addr) diff -u --recursive --new-file v2.4.1/linux/arch/mips64/lib/rtc-std.c linux/arch/mips64/lib/rtc-std.c --- v2.4.1/linux/arch/mips64/lib/rtc-std.c Sat May 13 08:30:17 2000 +++ linux/arch/mips64/lib/rtc-std.c Sun Feb 4 21:48:46 2001 @@ -1,5 +1,4 @@ -/* $Id: rtc-std.c,v 1.1 1999/08/21 21:43:01 ralf Exp $ - * +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -8,6 +7,7 @@ * * Copyright (C) 1998 by Ralf Baechle */ +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips64/mm/Makefile linux/arch/mips64/mm/Makefile --- v2.4.1/linux/arch/mips64/mm/Makefile Sat May 13 08:30:17 2000 +++ linux/arch/mips64/mm/Makefile Sun Feb 4 21:48:46 2001 @@ -1,33 +1,16 @@ -# $Id: Makefile,v 1.4 2000/01/17 23:32:46 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 +obj-y := extable.o init.o fault.o loadmmu.o -ifdef CONFIG_SGI_IP22 -O_OBJS += umap.o -endif - -ifdef CONFIG_BAGET_MIPS -O_OBJS += umap.o -endif +obj-$(CONFIG_CPU_R4300) += r4xx0.o +obj-$(CONFIG_CPU_R4X00) += r4xx0.o +obj-$(CONFIG_CPU_R5000) += r4xx0.o +obj-$(CONFIG_CPU_NEVADA) += r4xx0.o +obj-$(CONFIG_CPU_R10000) += andes.o +obj-$(CONFIG_SGI_IP22) += umap.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/mips64/mm/r4xx0.c linux/arch/mips64/mm/r4xx0.c --- v2.4.1/linux/arch/mips64/mm/r4xx0.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/mm/r4xx0.c Sun Feb 4 21:48:46 2001 @@ -2129,7 +2129,6 @@ 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. */ diff -u --recursive --new-file v2.4.1/linux/arch/mips64/sgi-ip22/Makefile linux/arch/mips64/sgi-ip22/Makefile --- v2.4.1/linux/arch/mips64/sgi-ip22/Makefile Sat May 13 08:30:17 2000 +++ linux/arch/mips64/sgi-ip22/Makefile Sun Feb 4 21:48:46 2001 @@ -1,4 +1,3 @@ -# $Id: Makefile,v 1.1 1999/08/20 21:13:33 ralf Exp $ # # Makefile for the SGI specific kernel interface routines # under Linux. @@ -10,7 +9,8 @@ $(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 + +obj-y += ip22-berr.o ip22-mc.o ip22-sc.o ip22-hpc.o ip22-int.o ip22-rtc.o \ + ip22-setup.o system.o ip22-timer.o ip22-irq.o ip22-reset.o time.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/mips64/sgi-ip22/ip22-int.c linux/arch/mips64/sgi-ip22/ip22-int.c --- v2.4.1/linux/arch/mips64/sgi-ip22/ip22-int.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/sgi-ip22/ip22-int.c Fri Feb 9 11:29:44 2001 @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/mips64/sgi-ip27/Makefile linux/arch/mips64/sgi-ip27/Makefile --- v2.4.1/linux/arch/mips64/sgi-ip27/Makefile Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/sgi-ip27/Makefile Sun Feb 4 21:48:46 2001 @@ -8,8 +8,9 @@ $(CC) $(CFLAGS) -c $< -o $*.o O_TARGET = ip27.a -O_OBJS = ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \ - ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-pci.o \ - ip27-pci-dma.o ip27-reset.o ip27-setup.o ip27-timer.o + +obj-y := ip27-berr.o ip27-console.o ip27-irq.o ip27-init.o ip27-irq-glue.o \ + ip27-klconfig.o ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-pci.o \ + ip27-pci-dma.o ip27-reset.o ip27-setup.o ip27-timer.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/mips64/sgi-ip27/ip27-init.c linux/arch/mips64/sgi-ip27/ip27-init.c --- v2.4.1/linux/arch/mips64/sgi-ip27/ip27-init.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/sgi-ip27/ip27-init.c Sun Feb 4 21:48:46 2001 @@ -472,9 +472,9 @@ sprintf(p->comm, "%s%d", "Idle", num_cpus); init_tasks[num_cpus] = p; alloc_cpupda(cpu, num_cpus); + del_from_runqueue(p); p->processor = num_cpus; p->has_cpu = 1; /* we schedule the first task manually */ - del_from_runqueue(p); unhash_process(p); /* Attach to the address space of init_task. */ atomic_inc(&init_mm.mm_count); diff -u --recursive --new-file v2.4.1/linux/arch/mips64/sgi-ip27/ip27-irq.c linux/arch/mips64/sgi-ip27/ip27-irq.c --- v2.4.1/linux/arch/mips64/sgi-ip27/ip27-irq.c Tue Nov 28 21:42:04 2000 +++ linux/arch/mips64/sgi-ip27/ip27-irq.c Fri Feb 9 11:29:44 2001 @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/parisc/kernel/ccio-dma.c linux/arch/parisc/kernel/ccio-dma.c --- v2.4.1/linux/arch/parisc/kernel/ccio-dma.c Wed Dec 6 11:46:39 2000 +++ linux/arch/parisc/kernel/ccio-dma.c Fri Feb 9 11:29:44 2001 @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/parisc/kernel/iosapic.c linux/arch/parisc/kernel/iosapic.c --- v2.4.1/linux/arch/parisc/kernel/iosapic.c Wed Dec 6 11:46:39 2000 +++ linux/arch/parisc/kernel/iosapic.c Fri Feb 9 11:29:44 2001 @@ -162,7 +162,7 @@ #include #include /* pci cfg accessor functions */ #include -#include +#include #include #include /* irqaction */ #include /* irq_region support */ diff -u --recursive --new-file v2.4.1/linux/arch/parisc/kernel/irq.c linux/arch/parisc/kernel/irq.c --- v2.4.1/linux/arch/parisc/kernel/irq.c Wed Dec 6 11:46:39 2000 +++ linux/arch/parisc/kernel/irq.c Fri Feb 9 11:29:44 2001 @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/parisc/kernel/lba_pci.c linux/arch/parisc/kernel/lba_pci.c --- v2.4.1/linux/arch/parisc/kernel/lba_pci.c Wed Dec 6 11:46:39 2000 +++ linux/arch/parisc/kernel/lba_pci.c Fri Feb 9 11:29:44 2001 @@ -36,7 +36,7 @@ #include /* for __init and __devinit */ #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/parisc/kernel/pci-dma.c linux/arch/parisc/kernel/pci-dma.c --- v2.4.1/linux/arch/parisc/kernel/pci-dma.c Tue Dec 5 12:29:39 2000 +++ linux/arch/parisc/kernel/pci-dma.c Fri Feb 9 11:29:44 2001 @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/parisc/kernel/process.c linux/arch/parisc/kernel/process.c --- v2.4.1/linux/arch/parisc/kernel/process.c Wed Dec 6 11:46:39 2000 +++ linux/arch/parisc/kernel/process.c Fri Feb 9 11:29:44 2001 @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/parisc/kernel/sba_iommu.c linux/arch/parisc/kernel/sba_iommu.c --- v2.4.1/linux/arch/parisc/kernel/sba_iommu.c Tue Dec 5 12:29:39 2000 +++ linux/arch/parisc/kernel/sba_iommu.c Fri Feb 9 11:29:44 2001 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/parisc/kernel/setup.c linux/arch/parisc/kernel/setup.c --- v2.4.1/linux/arch/parisc/kernel/setup.c Wed Dec 6 11:46:39 2000 +++ linux/arch/parisc/kernel/setup.c Fri Feb 9 11:29:44 2001 @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/parisc/mm/kmap.c linux/arch/parisc/mm/kmap.c --- v2.4.1/linux/arch/parisc/mm/kmap.c Tue Dec 5 12:29:39 2000 +++ linux/arch/parisc/mm/kmap.c Fri Feb 9 11:29:44 2001 @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/8260_io/enet.c linux/arch/ppc/8260_io/enet.c --- v2.4.1/linux/arch/ppc/8260_io/enet.c Sat Feb 3 19:51:22 2001 +++ linux/arch/ppc/8260_io/enet.c Fri Feb 9 11:29:44 2001 @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/8260_io/fcc_enet.c linux/arch/ppc/8260_io/fcc_enet.c --- v2.4.1/linux/arch/ppc/8260_io/fcc_enet.c Sat Feb 3 19:51:22 2001 +++ linux/arch/ppc/8260_io/fcc_enet.c Fri Feb 16 16:02:34 2001 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -46,7 +46,7 @@ #define TX_TIMEOUT (2*HZ) /* The number of Tx and Rx buffers. These are allocated from the page - * pool. The code may assume these are power of two, so it it best + * pool. The code may assume these are power of two, so it is best * to keep them that size. * We don't need to allocate pages for the transmitter. We just use * the skbuffer directly. diff -u --recursive --new-file v2.4.1/linux/arch/ppc/8260_io/uart.c linux/arch/ppc/8260_io/uart.c --- v2.4.1/linux/arch/ppc/8260_io/uart.c Wed Dec 6 12:06:18 2000 +++ linux/arch/ppc/8260_io/uart.c Fri Feb 9 11:29:44 2001 @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/8xx_io/commproc.h linux/arch/ppc/8xx_io/commproc.h --- v2.4.1/linux/arch/ppc/8xx_io/commproc.h Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/8xx_io/commproc.h Fri Feb 16 16:02:34 2001 @@ -76,7 +76,7 @@ uint cbd_bufaddr; /* Buffer address in host memory */ } cbd_t; -#define BD_SC_EMPTY ((ushort)0x8000) /* Recieve is empty */ +#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ #define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ #define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ #define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ diff -u --recursive --new-file v2.4.1/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c --- v2.4.1/linux/arch/ppc/8xx_io/enet.c Sat Feb 3 19:51:22 2001 +++ linux/arch/ppc/8xx_io/enet.c Fri Feb 9 11:29:44 2001 @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c --- v2.4.1/linux/arch/ppc/8xx_io/fec.c Sat Feb 3 19:51:22 2001 +++ linux/arch/ppc/8xx_io/fec.c Fri Feb 16 16:02:34 2001 @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include @@ -73,7 +73,7 @@ } phy_info_t; /* The number of Tx and Rx buffers. These are allocated from the page - * pool. The code may assume these are power of two, so it it best + * pool. The code may assume these are power of two, so it is best * to keep them that size. * We don't need to allocate pages for the transmitter. We just use * the skbuffer directly. @@ -953,7 +953,7 @@ /* * I had some nice ideas of running the MDIO faster... * The 971 should support 8MHz and I tried it, but things acted really - * wierd, so 2.5 MHz ought to be enough for anyone... + * weird, so 2.5 MHz ought to be enough for anyone... */ static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) diff -u --recursive --new-file v2.4.1/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c --- v2.4.1/linux/arch/ppc/8xx_io/uart.c Wed Dec 6 12:06:18 2000 +++ linux/arch/ppc/8xx_io/uart.c Fri Feb 9 11:29:44 2001 @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c --- v2.4.1/linux/arch/ppc/amiga/amiints.c Wed Feb 9 19:43:47 2000 +++ linux/arch/ppc/amiga/amiints.c Fri Feb 16 16:02:34 2001 @@ -119,7 +119,7 @@ custom.intreq = 0x7fff; #ifdef CONFIG_APUS - /* Clear any inter-CPU interupt requests. Circumvents bug in + /* Clear any inter-CPU interrupt requests. Circumvents bug in Blizzard IPL emulation HW (or so it appears). */ APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/checks.c linux/arch/ppc/kernel/checks.c --- v2.4.1/linux/arch/ppc/kernel/checks.c Wed May 26 16:55:40 1999 +++ linux/arch/ppc/kernel/checks.c Fri Feb 9 11:29:44 2001 @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.4.1/linux/arch/ppc/kernel/chrp_setup.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/chrp_setup.c Tue Feb 13 13:15:04 2001 @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.4.1/linux/arch/ppc/kernel/idle.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/idle.c Fri Feb 9 11:29:44 2001 @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.4.1/linux/arch/ppc/kernel/irq.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/irq.c Fri Feb 9 11:29:44 2001 @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/m8260_setup.c linux/arch/ppc/kernel/m8260_setup.c --- v2.4.1/linux/arch/ppc/kernel/m8260_setup.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/m8260_setup.c Fri Feb 9 11:29:44 2001 @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c --- v2.4.1/linux/arch/ppc/kernel/m8xx_setup.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/m8xx_setup.c Fri Feb 9 11:29:44 2001 @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.4.1/linux/arch/ppc/kernel/pmac_pic.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/pmac_pic.c Fri Feb 16 16:02:34 2001 @@ -457,7 +457,7 @@ /* * These procedures are used in implementing sleep on the powerbooks. * sleep_save_intrs() saves the states of all interrupt enables - * and disables all interupts except for the nominated one. + * and disables all interrupts except for the nominated one. * sleep_restore_intrs() restores the states of all interrupt enables. */ unsigned int sleep_save_mask[2]; diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.4.1/linux/arch/ppc/kernel/pmac_setup.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/pmac_setup.c Fri Feb 9 11:29:44 2001 @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.4.1/linux/arch/ppc/kernel/ppc_ksyms.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/ppc_ksyms.c Tue Feb 13 13:15:04 2001 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/prep_nvram.c linux/arch/ppc/kernel/prep_nvram.c --- v2.4.1/linux/arch/ppc/kernel/prep_nvram.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/prep_nvram.c Fri Feb 9 11:29:44 2001 @@ -6,7 +6,7 @@ */ #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.4.1/linux/arch/ppc/kernel/prep_setup.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/prep_setup.c Fri Feb 9 11:29:44 2001 @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.4.1/linux/arch/ppc/kernel/process.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/process.c Fri Feb 9 11:29:44 2001 @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/residual.c linux/arch/ppc/kernel/residual.c --- v2.4.1/linux/arch/ppc/kernel/residual.c Tue Oct 12 10:00:58 1999 +++ linux/arch/ppc/kernel/residual.c Fri Feb 9 11:29:44 2001 @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.4.1/linux/arch/ppc/kernel/setup.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/setup.c Tue Feb 13 13:15:04 2001 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/softemu8xx.c linux/arch/ppc/kernel/softemu8xx.c --- v2.4.1/linux/arch/ppc/kernel/softemu8xx.c Tue Aug 31 11:36:43 1999 +++ linux/arch/ppc/kernel/softemu8xx.c Fri Feb 9 11:29:44 2001 @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c --- v2.4.1/linux/arch/ppc/kernel/traps.c Sat Feb 3 19:51:23 2001 +++ linux/arch/ppc/kernel/traps.c Fri Feb 9 11:29:44 2001 @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.1/linux/arch/s390/Makefile linux/arch/s390/Makefile --- v2.4.1/linux/arch/s390/Makefile Fri May 12 11:41:44 2000 +++ linux/arch/s390/Makefile Tue Feb 13 14:13:43 2001 @@ -14,6 +14,7 @@ # LD=$(CROSS_COMPILE)ld -m elf_s390 +CPP=$(CC) -E OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S LDFLAGS=-e start LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux.lds $(LDFLAGS) diff -u --recursive --new-file v2.4.1/linux/arch/s390/boot/Makefile linux/arch/s390/boot/Makefile --- v2.4.1/linux/arch/s390/boot/Makefile Fri May 12 11:41:44 2000 +++ linux/arch/s390/boot/Makefile Tue Feb 13 14:13:43 2001 @@ -10,12 +10,11 @@ OBJCOPY = $(CROSS_COMPILE)objcopy O_TARGET := -O_OBJS := include $(TOPDIR)/Rules.make .S.o: - $(CC) $(AFLAGS) -traditional -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o %.lnk: %.o $(LD) -Ttext 0x0 -o $@ $< diff -u --recursive --new-file v2.4.1/linux/arch/s390/boot/ipldump.S linux/arch/s390/boot/ipldump.S --- v2.4.1/linux/arch/s390/boot/ipldump.S Fri May 12 11:41:44 2000 +++ linux/arch/s390/boot/ipldump.S Tue Feb 13 14:13:43 2001 @@ -38,7 +38,7 @@ # # find out memory size # - mvc 104(8,0),.Lpcmem0 # setup program check handler + mvc 104(8),.Lpcmem0 # setup program check handler slr %r3,%r3 lhi %r2,1 sll %r2,20 diff -u --recursive --new-file v2.4.1/linux/arch/s390/boot/ipleckd.S linux/arch/s390/boot/ipleckd.S --- v2.4.1/linux/arch/s390/boot/ipleckd.S Fri May 12 11:41:44 2000 +++ linux/arch/s390/boot/ipleckd.S Tue Feb 13 14:13:43 2001 @@ -3,7 +3,7 @@ # IPL record for 3380/3390 DASD # # S390 version -# Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation +# Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation # Author(s): Holger Smolinski # # @@ -11,6 +11,8 @@ # FIXME: should insert zeroes into memory when filling holes # FIXME: calculate blkpertrack from rdc data and blksize +# change 09/20/00 removed obsolete store of ipldevice to textesegment + # Usage of registers # r1: ipl subchannel ( general use, dont overload without save/restore !) # r10: @@ -39,7 +41,7 @@ .org 0xf0 # Lets start now... _start: .globl _start - l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore + l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore st %r1,__LC_IPLDEV # keep it for reipl stsch .Lrdcdata oi .Lrdcdata+5,0x84 # enable ssch and multipath mode @@ -111,10 +113,10 @@ mvc 0x600(256,%r3),0x180(%r4) mvc 0x700(256,%r3),0x280(%r4) .Lrunkern: - lhi %r2,17 - sll %r2,12 - st %r1,0xc6c(%r2) # store iplsubchannel to lowcore - st %r1,0xc6c # store iplsubchannel to lowcore +# lhi %r2,17 +# sll %r2,12 +# st %r1,0xc6c(%r2) # store iplsubchannel to lowcore +# st %r1,0xc6c # store iplsubchannel to lowcore br %r3 # This function does the start IO # r2: number of first block to read ( input by caller ) @@ -140,17 +142,16 @@ lr %r15,%r4 # save number or blocks slr %r7,%r7 icm %r7,3,.Lrdcdata+14 # load heads to r7 + lhi %r6,9 + clc .Lrdcdata+3(2),.L9345 + je .L011 + lhi %r6,10 + clc .Lrdcdata+3(2),.L3380 + je .L011 + lhi %r6,12 clc .Lrdcdata+3(2),.L3390 - jne .L010 # 3380 or 3390 ? - lhi %r6,12 # setup r6 correct! - j .L011 -.L010: - clc .Lrdcdata+3(2),.L9343 - jne .L013 - lhi %r6,9 - j .L011 -.L013: - lhi %r6,10 + je .L011 + bras %r14,.Ldisab .L011: # loop for nbl times .Lrdloop: @@ -245,10 +246,13 @@ .long 0x00008000 # they are loaded with a LM .L3390: .word 0x3390 -.L9343: - .word 0x9343 +.L9345: + .word 0x9345 +.L3380: + .word 0x3380 .Lnull: .long 0x00000000,0x00000000 + .align 4 .Lrdcdata: .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 diff -u --recursive --new-file v2.4.1/linux/arch/s390/config.in linux/arch/s390/config.in --- v2.4.1/linux/arch/s390/config.in Thu Nov 16 12:51:28 2000 +++ linux/arch/s390/config.in Tue Feb 13 14:13:43 2001 @@ -44,30 +44,19 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +define CONFIG_KCORE ELF tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF - +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG endmenu source drivers/s390/Config.in -mainmenu_option next_comment -comment 'Character devices' -bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS -if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 -fi - -endmenu - if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi source fs/Config.in - -# source drivers/char/Config.in - -# source drivers/media/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -u --recursive --new-file v2.4.1/linux/arch/s390/defconfig linux/arch/s390/defconfig --- v2.4.1/linux/arch/s390/defconfig Mon Jun 19 13:25:06 2000 +++ linux/arch/s390/defconfig Tue Feb 13 14:13:43 2001 @@ -1,6 +1,9 @@ # # Automatically generated by make menuconfig: don't edit # +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set CONFIG_UID16=y CONFIG_ARCH_S390=y @@ -20,7 +23,7 @@ # CONFIG_MODULES=y # CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set +CONFIG_KMOD=y # # General setup @@ -34,41 +37,60 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PROCESS_DEBUG is not set # -# S/390 block device drivers +# Block device drivers # CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=24576 CONFIG_BLK_DEV_INITRD=y -# CONFIG_MDISK is not set +CONFIG_BLK_DEV_XPRAM=m CONFIG_DASD=y CONFIG_DASD_ECKD=y -# CONFIG_DASD_MDSK is not set +CONFIG_DASD_FBA=y # -# S/390 Network device support +# Multi-device support (RAID and LVM) # -# CONFIG_CHANDEV is not set -CONFIG_NETDEVICES=y -CONFIG_CTC=y -CONFIG_IUCV=y -# CONFIG_DUMMY is not set -CONFIG_NET_ETHERNET=y -CONFIG_TR=y -# CONFIG_FDDI is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +# CONFIG_MD_LINEAR is not set +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_BLK_DEV_LVM=m +CONFIG_LVM_PROC_FS=y # -# S/390 Terminal and Console options +# Character device drivers # +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 CONFIG_3215=y CONFIG_3215_CONSOLE=y CONFIG_HWC=y CONFIG_HWC_CONSOLE=y -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_S390_TAPE=m +CONFIG_S390_TAPE_CHAR=y +CONFIG_S390_TAPE_BLOCK=y +CONFIG_S390_TAPE_3490=y +CONFIG_S390_TAPE_3480=y + +# +# Network device drivers +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +CONFIG_NET_ETHERNET=y +CONFIG_TR=y +# CONFIG_FDDI is not set +# CONFIG_CHANDEV is not set +CONFIG_CTC=m +CONFIG_IUCV=m # # Networking options @@ -82,25 +104,24 @@ # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP 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_INET_ECN is not set # CONFIG_SYN_COOKIES is not set -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE is not set # CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set @@ -118,6 +139,7 @@ # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set # CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set @@ -126,28 +148,37 @@ # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set # CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_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_NFS_V3 is not set # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set @@ -155,6 +186,16 @@ CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types @@ -168,10 +209,10 @@ # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # # Kernel hacking # -# CONFIG_REMOTE_DEBUG is not set diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/Makefile linux/arch/s390/kernel/Makefile --- v2.4.1/linux/arch/s390/kernel/Makefile Fri May 12 11:41:44 2000 +++ linux/arch/s390/kernel/Makefile Tue Feb 13 14:13:43 2001 @@ -8,47 +8,25 @@ # Note 2! The CFLAGS definitions are now in the main makefile... .S.o: - $(CC) $(AFLAGS) -traditional -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o all: kernel.o head.o init_task.o O_TARGET := kernel.o -O_OBJS := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \ - setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390fpu.o s390io.o s390mach.o s390dyn.o reipl.o -OX_OBJS := s390_ksyms.o -MX_OBJS := - -ifdef CONFIG_SMP -O_OBJS += smp.o -endif - -ifdef CONFIG_PCI -O_OBJS += bios32.o -endif -ifdef CONFIG_MCA -O_OBJS += mca.o -endif - -ifeq ($(CONFIG_MTRR),y) -OX_OBJS += mtrr.o -else - ifeq ($(CONFIG_MTRR),m) - MX_OBJS += mtrr.o - endif -endif +export-objs := s390_ksyms.o +obj-y := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \ + setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ + semaphore.o s390fpu.o reipl.o s390_ext.o debug.o -ifeq ($(CONFIG_IEEEFPU_EMULATION),y) - O_OBJS += mathemu.o floatlib.o -endif +obj-$(CONFIG_MODULES) += s390_ksyms.o +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_IEEEFPU_EMULATION) += mathemu.o floatlib.o # # Kernel debugging # -ifdef CONFIG_REMOTE_DEBUG -O_OBJS += gdb-stub.o #gdb-low.o -endif +obj-$(CONFIG_REMOTE_DEBUG) += gdb-stub.o #gdb-low.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/cpcmd.c linux/arch/s390/kernel/cpcmd.c --- v2.4.1/linux/arch/s390/kernel/cpcmd.c Fri May 12 11:41:44 2000 +++ linux/arch/s390/kernel/cpcmd.c Tue Feb 13 14:13:43 2001 @@ -8,7 +8,7 @@ #include #include -#include +#include #include void cpcmd(char *cmd, char *response, int rlen) @@ -22,10 +22,10 @@ ASCEBC(obuffer,olen); if (response != NULL && rlen > 0) { - asm volatile ("LRA 2,0(0,%0)\n\t" + asm volatile ("LRA 2,0(%0)\n\t" "LR 4,%1\n\t" "O 4,%4\n\t" - "LRA 3,0(0,%2)\n\t" + "LRA 3,0(%2)\n\t" "LR 5,%3\n\t" ".long 0x83240008 # Diagnose 83\n\t" : /* no output */ @@ -34,7 +34,7 @@ : "2", "3", "4", "5" ); EBCASC(response, rlen); } else { - asm volatile ("LRA 2,0(0,%0)\n\t" + asm volatile ("LRA 2,0(%0)\n\t" "LR 3,%1\n\t" ".long 0x83230008 # Diagnose 83\n\t" : /* no output */ diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c --- v2.4.1/linux/arch/s390/kernel/debug.c Wed Dec 31 16:00:00 1969 +++ linux/arch/s390/kernel/debug.c Tue Feb 13 14:13:43 2001 @@ -0,0 +1,1167 @@ +/* + * arch/s390/kernel/debug.c + * S/390 debug facility + * + * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, + * IBM Corporation + * Author(s): Michael Holzheu (holzheu@de.ibm.com), + * Holger Smolinski (Holger.Smolinski@de.ibm.com) + * + * Bugreports to: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef MODULE +#include +#endif + +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +#if defined(CONFIG_ARCH_S390X) +#define DEBUG_PROC_HEADER_SIZE 46 +#else +#define DEBUG_PROC_HEADER_SIZE 38 +#endif + +#define ADD_BUFFER 1000 + +/* typedefs */ + +typedef struct file_private_info { + loff_t len; /* length of output in byte */ + int size; /* size of buffer for output */ + char *data; /* buffer for output */ + debug_info_t *debug_info; /* the debug information struct */ + struct debug_view *view; /* used view of debug info */ +} file_private_info_t; + +extern void tod_to_timeval(uint64_t todval, struct timeval *xtime); + +/* internal function prototyes */ + +static int debug_init(void); +static int debug_format_output(debug_info_t * debug_area, char *buf, + int size, struct debug_view *view); +static ssize_t debug_output(struct file *file, char *user_buf, + size_t user_len, loff_t * offset); +static ssize_t debug_input(struct file *file, const char *user_buf, + size_t user_len, loff_t * offset); +static int debug_open(struct inode *inode, struct file *file); +static int debug_close(struct inode *inode, struct file *file); +static struct proc_dir_entry +*debug_create_proc_dir_entry(struct proc_dir_entry *root, + const char *name, mode_t mode, + struct inode_operations *iops, + struct file_operations *fops); +static void debug_delete_proc_dir_entry(struct proc_dir_entry *root, + struct proc_dir_entry *entry); +static debug_info_t* debug_info_create(char *name, int page_order, int nr_areas, int buf_size); +static void debug_info_get(debug_info_t *); +static void debug_info_put(debug_info_t *); +static int debug_prolog_level_fn(debug_info_t * id, + struct debug_view *view, char *out_buf); +static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, + struct file *file, const char *user_buf, + size_t user_buf_size, loff_t * offset); +static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf); +static int debug_raw_format_fn(debug_info_t * id, + struct debug_view *view, char *out_buf, + const char *in_buf); +static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf); + +/* globals */ + +struct debug_view debug_raw_view = { + "raw", + NULL, + &debug_raw_header_fn, + &debug_raw_format_fn, + NULL +}; + +struct debug_view debug_hex_ascii_view = { + "hex_ascii", + NULL, + &debug_dflt_header_fn, + &debug_hex_ascii_format_fn, + NULL +}; + +struct debug_view debug_level_view = { + "level", + &debug_prolog_level_fn, + NULL, + NULL, + &debug_input_level_fn +}; + +/* static globals */ + +static debug_info_t *debug_area_first = NULL; +static debug_info_t *debug_area_last = NULL; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) +static struct semaphore debug_lock = MUTEX; +#else +DECLARE_MUTEX(debug_lock); +#endif + +static int initialized = 0; + +static struct file_operations debug_file_ops = { + read: debug_output, + write: debug_input, + open: debug_open, + release: debug_close, +}; + +static struct inode_operations debug_inode_ops = { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) + default_file_ops: &debug_file_ops, /* file ops */ +#endif +}; + + +static struct proc_dir_entry *debug_proc_root_entry; + + +/* functions */ + +/* + * debug_info_create + * - create new debug-info + */ + +static debug_info_t* debug_info_create(char *name, int page_order, + int nr_areas, int buf_size) +{ + debug_info_t* rc; + int i; + + /* alloc everything */ + + rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); + if(!rc) + goto fail_malloc_rc; + rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC); + if(!rc->active_entry) + goto fail_malloc_active_entry; + memset(rc->active_entry, 0, nr_areas * sizeof(int)); + rc->areas = (debug_entry_t **) kmalloc(nr_areas * + sizeof(debug_entry_t *), + GFP_ATOMIC); + if (!rc->areas) + goto fail_malloc_areas; + for (i = 0; i < nr_areas; i++) { + rc->areas[i] = + (debug_entry_t *) __get_free_pages(GFP_ATOMIC, + page_order); + if (!rc->areas[i]) { + for (i--; i >= 0; i--) { + free_pages((unsigned long) rc->areas[i], + page_order); + } + goto fail_malloc_areas2; + } else { + memset(rc->areas[i], 0, PAGE_SIZE << page_order); + } + } + + /* initialize members */ + + spin_lock_init(&rc->lock); + rc->page_order = page_order; + rc->nr_areas = nr_areas; + rc->active_area = 0; + rc->level = DEBUG_DEFAULT_LEVEL; + rc->buf_size = buf_size; + rc->entry_size = sizeof(debug_entry_t) + buf_size; + strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))); + rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0; + memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); + memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * + sizeof(struct proc_dir_entry*)); + atomic_set(&(rc->ref_count), 0); + rc->proc_root_entry = + debug_create_proc_dir_entry(debug_proc_root_entry, rc->name, + S_IFDIR | S_IRUGO | S_IXUGO | + S_IWUSR | S_IWGRP, NULL, NULL); + + /* append new element to linked list */ + + if(debug_area_first == NULL){ + /* first element in list */ + debug_area_first = rc; + rc->prev = NULL; + } + else{ + /* append element to end of list */ + debug_area_last->next = rc; + rc->prev = debug_area_last; + } + debug_area_last = rc; + rc->next = NULL; + + debug_info_get(rc); + return rc; + +fail_malloc_areas2: + kfree(rc->areas); +fail_malloc_areas: + kfree(rc->active_entry); +fail_malloc_active_entry: + kfree(rc); +fail_malloc_rc: + return NULL; +} + +/* + * debug_info_get + * - increments reference count for debug-info + */ + +static void debug_info_get(debug_info_t * db_info) +{ + if (db_info) + atomic_inc(&db_info->ref_count); +} + +/* + * debug_info_put: + * - decreases reference count for debug-info and frees it if necessary + */ + +static void debug_info_put(debug_info_t *db_info) +{ + int i; + + if (!db_info) + return; + if (atomic_dec_and_test(&db_info->ref_count)) { + printk(KERN_INFO "debug: freeing debug area %p (%s)\n", + db_info, db_info->name); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (db_info->views[i] != NULL) + debug_delete_proc_dir_entry + (db_info->proc_root_entry, + db_info->proc_entries[i]); + } + debug_delete_proc_dir_entry(debug_proc_root_entry, + db_info->proc_root_entry); + for (i = 0; i < db_info->nr_areas; i++) { + free_pages((unsigned long) db_info->areas[i], + db_info->page_order); + } + kfree(db_info->areas); + kfree(db_info->active_entry); + if(db_info == debug_area_first) + debug_area_first = db_info->next; + if(db_info == debug_area_last) + debug_area_last = db_info->prev; + if(db_info->prev) db_info->prev->next = db_info->next; + if(db_info->next) db_info->next->prev = db_info->prev; + kfree(db_info); + } +} + + +/* + * debug_output: + * - called for user read() + * - copies formated output form private_data of the file + * handle to the user buffer + */ + +static ssize_t debug_output(struct file *file, /* file descriptor */ + char *user_buf, /* user buffer */ + size_t user_len, /* length of buffer */ + loff_t *offset /* offset in the file */ ) +{ + loff_t len; + int rc; + file_private_info_t *p_info; + + p_info = ((file_private_info_t *) file->private_data); + if (*offset >= p_info->len) { + return 0; /* EOF */ + } else { + len = MIN(user_len, (p_info->len - *offset)); + if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len))) + return rc;; + (*offset) += len; + return len; /* number of bytes "read" */ + } +} + +/* + * debug_input: + * - called for user write() + * - calls input function of view + */ + +static ssize_t debug_input(struct file *file, + const char *user_buf, size_t length, + loff_t *offset) +{ + int rc = 0; + file_private_info_t *p_info; + + down(&debug_lock); + p_info = ((file_private_info_t *) file->private_data); + if (p_info->view->input_proc) + rc = p_info->view->input_proc(p_info->debug_info, + p_info->view, file, user_buf, + length, offset); + up(&debug_lock); + return rc; /* number of input characters */ +} + +/* + * debug_format_output: + * - calls prolog, header and format functions of view to format output + */ + +static int debug_format_output(debug_info_t * debug_area, char *buf, + int size, struct debug_view *view) +{ + int len = 0; + int i, j; + int nr_of_entries; + debug_entry_t *act_entry; + + /* print prolog */ + if (view->prolog_proc) + len += view->prolog_proc(debug_area, view, buf); + /* print debug records */ + if (!(view->format_proc) && !(view->header_proc)) + goto out; + nr_of_entries = PAGE_SIZE / debug_area->entry_size + << debug_area->page_order; + for (i = 0; i < debug_area->nr_areas; i++) { + act_entry = debug_area->areas[i]; + for (j = 0; j < nr_of_entries; j++) { + if (act_entry->id.fields.used == 0) + break; /* empty entry */ + if (view->header_proc) + len += view->header_proc(debug_area, view, i, + act_entry, buf + len); + if (view->format_proc) + len += view->format_proc(debug_area, view, + buf + len, + DEBUG_DATA(act_entry)); + if (len > size) { + printk(KERN_ERR + "debug: error -- memory exceeded for (%s/%s)\n", + debug_area->name, view->name); + printk(KERN_ERR "debug: fix view %s!!\n", + view->name); + printk(KERN_ERR + "debug: area: %i (0 - %i) entry: %i (0 - %i)\n", + i, debug_area->nr_areas - 1, j, + nr_of_entries - 1); + goto out; + } + act_entry = (debug_entry_t *) (((char *) act_entry) + + debug_area->entry_size); + } + } + out: + return len; +} + + +/* + * debug_open: + * - called for user open() + * - copies formated output to private_data area of the file + * handle + */ + +static int debug_open(struct inode *inode, struct file *file) +{ + int i = 0, size = 0, rc = 0, f_entry_size = 0; + file_private_info_t *p_info; + debug_info_t* debug_info; + +#ifdef DEBUG + printk("debug_open\n"); +#endif + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + down(&debug_lock); + + /* find debug log and view */ + + debug_info = debug_area_first; + while(debug_info != NULL){ + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (debug_info->views[i] == NULL) + continue; + else if (debug_info->proc_entries[i]->low_ino == + file->f_dentry->d_inode->i_ino) { + goto found; /* found view ! */ + } + } + debug_info = debug_info->next; + } + /* no entry found */ + rc = -EINVAL; + goto out; + found: + if ((file->private_data = + kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { + printk(KERN_ERR "debug_open: kmalloc failed\n"); + rc = -ENOMEM; + goto out; + } + p_info = (file_private_info_t *) file->private_data; + + /* + * the size for the formated output is calculated + * with the following formula: + * + * prolog-size + * + + * (record header size + record data field size) + * * number of entries per page + * * number of pages per area + * * number of areas + */ + + if (debug_info->views[i]->prolog_proc) + size += + debug_info->views[i]->prolog_proc(debug_info, + debug_info-> + views[i], NULL); + + if (debug_info->views[i]->header_proc) + f_entry_size = + debug_info->views[i]->header_proc(debug_info, + debug_info-> + views[i], 0, NULL, + NULL); + if (debug_info->views[i]->format_proc) + f_entry_size += + debug_info->views[i]->format_proc(debug_info, + debug_info-> + views[i], NULL, + NULL); + + size += f_entry_size + * (PAGE_SIZE / debug_info->entry_size + << debug_info->page_order) + * debug_info->nr_areas + 1; /* terminating \0 */ +#ifdef DEBUG + printk("debug_open: size: %i\n", size); +#endif + + /* alloc some bytes more to be safe against bad views */ + if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) { + printk(KERN_ERR "debug_open: vmalloc failed\n"); + vfree(file->private_data); + rc = -ENOMEM; + goto out; + } + + p_info->size = size; + p_info->debug_info = debug_info; + p_info->view = debug_info->views[i]; + + spin_lock_irq(&debug_info->lock); + + p_info->len = + debug_format_output(debug_info, p_info->data, size, + debug_info->views[i]); +#ifdef DEBUG + { + int ilen = p_info->len; + printk("debug_open: len: %i\n", ilen); + } +#endif + + spin_unlock_irq(&debug_info->lock); + debug_info_get(debug_info); + + out: + up(&debug_lock); +#ifdef MODULE + if (rc != 0) + MOD_DEC_USE_COUNT; +#endif + return rc; +} + +/* + * debug_close: + * - called for user close() + * - deletes private_data area of the file handle + */ + +static int debug_close(struct inode *inode, struct file *file) +{ + file_private_info_t *p_info; +#ifdef DEBUG + printk("debug_close\n"); +#endif + down(&debug_lock); + p_info = (file_private_info_t *) file->private_data; + debug_info_put(p_info->debug_info); + if (p_info->data) { + vfree(p_info->data); + kfree(file->private_data); + } + up(&debug_lock); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; /* success */ +} + +/* + * debug_create_proc_dir_entry: + * - initializes proc-dir-entry and registers it + */ + +static struct proc_dir_entry *debug_create_proc_dir_entry + (struct proc_dir_entry *root, const char *name, mode_t mode, + struct inode_operations *iops, struct file_operations *fops) +{ + struct proc_dir_entry *rc = NULL; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) + const char *fn = name; + int len; + len = strlen(fn); + + rc = (struct proc_dir_entry *) kmalloc(sizeof(struct proc_dir_entry) + + len + 1, GFP_ATOMIC); + if (!rc) + goto out; + + memset(rc, 0, sizeof(struct proc_dir_entry)); + memcpy(((char *) rc) + sizeof(*rc), fn, len + 1); + rc->name = ((char *) rc) + sizeof(*rc); + rc->namelen = len; + rc->low_ino = 0, rc->mode = mode; + rc->nlink = 1; + rc->uid = 0; + rc->gid = 0; + rc->size = 0; + rc->get_info = NULL; + rc->ops = iops; + + proc_register(root, rc); +#else + rc = create_proc_entry(name, mode, root); + if (!rc) + goto out; + if (fops) + rc->proc_fops = fops; +#endif + + out: + return rc; +} + + +/* + * delete_proc_dir_entry: + */ + +static void debug_delete_proc_dir_entry + (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry) +{ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) + proc_unregister(root, proc_entry->low_ino); + kfree(proc_entry); +#else + remove_proc_entry(proc_entry->name, root); +#endif +} + +/* + * debug_register: + * - creates and initializes debug area for the caller + * - returns handle for debug area + */ + +debug_info_t *debug_register + (char *name, int page_order, int nr_areas, int buf_size) +{ + debug_info_t *rc = NULL; + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + if (!initialized) + debug_init(); + down(&debug_lock); + + /* create new debug_info */ + + rc = debug_info_create(name, page_order, nr_areas, buf_size); + if(!rc) + goto out; + debug_register_view(rc, &debug_level_view); + printk(KERN_INFO + "debug: reserved %d areas of %d pages for debugging %s\n", + nr_areas, 1 << page_order, rc->name); + out: + if (rc == NULL){ + printk(KERN_ERR "debug: debug_register failed for %s\n",name); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + } + up(&debug_lock); + return rc; +} + +/* + * debug_unregister: + * - give back debug area + */ + +void debug_unregister(debug_info_t * id) +{ + if (!id) + goto out; + down(&debug_lock); + printk(KERN_INFO "debug: unregistering %s\n", id->name); + debug_info_put(id); + up(&debug_lock); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + out: + return; +} + +/* + * debug_set_level: + * - set actual debug level + */ + +void debug_set_level(debug_info_t* id, int new_level) +{ + long flags; + if(!id) + return; + spin_lock_irqsave(&id->lock,flags); + if(new_level == DEBUG_OFF_LEVEL){ + id->level = DEBUG_OFF_LEVEL; + printk(KERN_INFO "debug: %s: switched off\n",id->name); + } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) { + printk(KERN_INFO + "debug: %s: level %i is out of range (%i - %i)\n", + id->name, new_level, 0, DEBUG_MAX_LEVEL); + } else { + id->level = new_level; + printk(KERN_INFO + "debug: %s: new level %i\n",id->name,id->level); + } + spin_unlock_irqrestore(&id->lock,flags); +} + + +/* + * proceed_active_entry: + * - set active entry to next in the ring buffer + */ + +static inline void proceed_active_entry(debug_info_t * id) +{ + if ((id->active_entry[id->active_area] += id->entry_size) + > ((PAGE_SIZE << (id->page_order)) - id->entry_size)) + id->active_entry[id->active_area] = 0; +} + +/* + * proceed_active_area: + * - set active area to next in the ring buffer + */ + +static inline void proceed_active_area(debug_info_t * id) +{ + id->active_area++; + id->active_area = id->active_area % id->nr_areas; +} + +/* + * get_active_entry: + */ + +static inline debug_entry_t *get_active_entry(debug_info_t * id) +{ + return (debug_entry_t *) ((char *) id->areas[id->active_area] + + id->active_entry[id->active_area]); +} + +/* + * debug_common: + * - set timestamp, caller address, cpu number etc. + */ + +static inline debug_entry_t *debug_common(debug_info_t * id) +{ + debug_entry_t *active; + + active = get_active_entry(id); + STCK(active->id.stck); + active->id.fields.cpuid = smp_processor_id(); + active->id.fields.used = 1; + active->caller = __builtin_return_address(0); + return active; +} + +/* + * debug_event: + */ + +debug_entry_t *debug_event(debug_info_t * id, int level, void *buf, + int len) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 0; + memset(DEBUG_DATA(active), 0, id->buf_size); + memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); + proceed_active_entry(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_int_event: + */ + +debug_entry_t *debug_int_event(debug_info_t * id, int level, + unsigned int tag) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 0; + memset(DEBUG_DATA(active), 0, id->buf_size); + memcpy(DEBUG_DATA(active), &tag, MIN(sizeof(unsigned int), id->buf_size)); + proceed_active_entry(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_text_event: + */ + +debug_entry_t *debug_text_event(debug_info_t * id, int level, + const char *txt) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + memset(DEBUG_DATA(active), 0, id->buf_size); + strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size)); + active->id.fields.exception = 0; + proceed_active_entry(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; + +} + +/* + * debug_exception: + */ + +debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf, + int len) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 1; + memset(DEBUG_DATA(active), 0, id->buf_size); + memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); + proceed_active_entry(id); + proceed_active_area(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_int_exception: + */ + +debug_entry_t *debug_int_exception(debug_info_t * id, int level, + unsigned int tag) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 1; + memset(DEBUG_DATA(active), 0, id->buf_size); + memcpy(DEBUG_DATA(active), &tag, + MIN(sizeof(unsigned int), id->buf_size)); + proceed_active_entry(id); + proceed_active_area(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_text_exception: + */ + +debug_entry_t *debug_text_exception(debug_info_t * id, int level, + const char *txt) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + memset(DEBUG_DATA(active), 0, id->buf_size); + strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size)); + active->id.fields.exception = 1; + proceed_active_entry(id); + proceed_active_area(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; + +} + +/* + * debug_init: + * - is called exactly once to initialize the debug feature + */ + +int debug_init(void) +{ + int rc = 0; + + down(&debug_lock); + if (!initialized) { + debug_proc_root_entry = + debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT, + S_IFDIR | S_IRUGO | S_IXUGO + | S_IWUSR | S_IWGRP, NULL, + NULL); + printk(KERN_INFO "debug: Initialization complete\n"); + initialized = 1; + } + up(&debug_lock); + + return rc; +} + +/* + * debug_register_view: + */ + +int debug_register_view(debug_info_t * id, struct debug_view *view) +{ + int rc = 0; + int i; + long flags; + mode_t mode = S_IFREG; + + if (!id) + goto out; + spin_lock_irqsave(&id->lock, flags); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (id->views[i] == NULL) + break; + } + if (i == DEBUG_MAX_VIEWS) { + printk(KERN_WARNING "debug: cannot register view %s/%s\n", + id->name,view->name); + printk(KERN_WARNING + "debug: maximum number of views reached (%i)!\n", i); + rc = -1; + } + else { + id->views[i] = view; + if (view->prolog_proc || view->format_proc || view->header_proc) + mode |= S_IRUSR; + if (view->input_proc) + mode |= S_IWUSR; + id->proc_entries[i] = + debug_create_proc_dir_entry(id->proc_root_entry, + view->name, mode, + &debug_inode_ops, + &debug_file_ops); + rc = 0; + } + spin_unlock_irqrestore(&id->lock, flags); + out: + return rc; +} + +/* + * debug_unregister_view: + */ + +int debug_unregister_view(debug_info_t * id, struct debug_view *view) +{ + int rc = 0; + int i; + long flags; + + if (!id) + goto out; + spin_lock_irqsave(&id->lock, flags); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (id->views[i] == view) + break; + } + if (i == DEBUG_MAX_VIEWS) + rc = -1; + else { + debug_delete_proc_dir_entry(id->proc_root_entry, + id->proc_entries[i]); + id->views[i] = NULL; + rc = 0; + } + spin_unlock_irqrestore(&id->lock, flags); + out: + return rc; +} + +/* + * functions for debug-views + *********************************** +*/ + +/* + * prints out actual debug level + */ + +static int debug_prolog_level_fn(debug_info_t * id, + struct debug_view *view, char *out_buf) +{ + int rc = 0; + + if (out_buf == NULL) { + rc = 2; + goto out; + } + if(id->level == -1) rc = sprintf(out_buf,"-\n"); + else rc = sprintf(out_buf, "%i\n", id->level); + out: + return rc; +} + +/* + * reads new debug level + */ + +static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, + struct file *file, const char *user_buf, + size_t in_buf_size, loff_t * offset) +{ + char input_buf[1]; + int rc = in_buf_size; + + if (*offset != 0) + goto out; + if ((rc = copy_from_user(input_buf, user_buf, 1))) + goto out; + if (isdigit(input_buf[0])) { + int new_level = ((int) input_buf[0] - (int) '0'); + debug_set_level(id, new_level); + } else if(input_buf[0] == '-') { + debug_set_level(id, DEBUG_OFF_LEVEL); + } else { + printk(KERN_INFO "debug: level `%c` is not valid\n", + input_buf[0]); + } + out: + *offset += in_buf_size; + return rc; /* number of input characters */ +} + +/* + * prints debug header in raw format + */ + +int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf) +{ + int rc; + + rc = sizeof(debug_entry_t); + if (out_buf == NULL) + goto out; + memcpy(out_buf,entry,sizeof(debug_entry_t)); + out: + return rc; +} + +/* + * prints debug data in raw format + */ + +static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) +{ + int rc; + + rc = id->buf_size; + if (out_buf == NULL || in_buf == NULL) + goto out; + memcpy(out_buf, in_buf, id->buf_size); + out: + return rc; +} + +/* + * prints debug data in hex/ascii format + */ + +static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) +{ + int i, rc = 0; + + if (out_buf == NULL || in_buf == NULL) { + rc = id->buf_size * 4 + 3; + goto out; + } + for (i = 0; i < id->buf_size; i++) { + rc += sprintf(out_buf + rc, "%02x ", + ((unsigned char *) in_buf)[i]); + } + rc += sprintf(out_buf + rc, "| "); + for (i = 0; i < id->buf_size; i++) { + unsigned char c = in_buf[i]; + if (!isprint(c)) + rc += sprintf(out_buf + rc, "."); + else + rc += sprintf(out_buf + rc, "%c", c); + } + rc += sprintf(out_buf + rc, "\n"); + out: + return rc; +} + +/* + * prints header for debug entry + */ + +int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf) +{ + struct timeval time_val; + unsigned long long time; + char *except_str; + unsigned long caller; + int rc = 0; + + if (out_buf == NULL) { + rc = DEBUG_PROC_HEADER_SIZE; + goto out; + } + + time = entry->id.stck; + /* adjust todclock to 1970 */ + time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); + tod_to_timeval(time, &time_val); + + if (entry->id.fields.exception) + except_str = "*"; + else + except_str = "-"; + caller = (unsigned long) entry->caller; +#if defined(CONFIG_ARCH_S390X) + rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %016lx ", + area, time_val.tv_sec, + time_val.tv_usec, except_str, + entry->id.fields.cpuid, caller); +#else + caller &= 0x7fffffff; + rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx ", + area, time_val.tv_sec, + time_val.tv_usec, except_str, + entry->id.fields.cpuid, caller); +#endif + out: + return rc; +} + +/* + * init_module: + */ + +#ifdef MODULE +int init_module(void) +{ + int rc = 0; +#ifdef DEBUG + printk("debug_module_init: \n"); +#endif + rc = debug_init(); + if (rc) + printk(KERN_INFO "debug: an error occurred with debug_init\n"); + return rc; +} + +/* + * cleanup_module: + */ + +void cleanup_module(void) +{ +#ifdef DEBUG + printk("debug_cleanup_module: \n"); +#endif + debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry); + return; +} + +#endif /* MODULE */ diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/ebcdic.c linux/arch/s390/kernel/ebcdic.c --- v2.4.1/linux/arch/s390/kernel/ebcdic.c Fri May 12 11:41:44 2000 +++ linux/arch/s390/kernel/ebcdic.c Tue Feb 13 14:13:43 2001 @@ -161,7 +161,156 @@ /* - * EBCDIC 037 conversion table: + * ASCII (IBM PC 437) -> EBCDIC 500 + */ +__u8 _ascebc_500[256] = +{ + /*00 NUL SOH STX ETX EOT ENQ ACK BEL */ + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + /*08 BS HT LF VT FF CR SO SI */ + /* ->NL */ + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + /*18 CAN EM SUB ESC FS GS RS US */ + /* ->IGS ->IRS ->IUS */ + 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, + /*20 SP ! " # $ % & ' */ + 0x40, 0x4F, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + /*28 ( ) * + , - . / */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + /*30 0 1 2 3 4 5 6 7 */ + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + /*38 8 9 : ; < = > ? */ + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + /*40 @ A B C D E F G */ + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + /*48 H I J K L M N O */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + /*50 P Q R S T U V W */ + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + /*58 X Y Z [ \ ] ^ _ */ + 0xE7, 0xE8, 0xE9, 0x4A, 0xE0, 0x5A, 0x5F, 0x6D, + /*60 ` a b c d e f g */ + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + /*68 h i j k l m n o */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + /*70 p q r s t u v w */ + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + /*78 x y z { | } ~ DL */ + 0xA7, 0xA8, 0xA9, 0xC0, 0xBB, 0xD0, 0xA1, 0x07, + /*80*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*88*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*90*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*98*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*A0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*A8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*B0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*B8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*C0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*C8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*D0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*D8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*E0 sz */ + 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*E8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*F0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*F8*/ + 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF +}; + +/* + * EBCDIC 500 -> ASCII (IBM PC 437) + */ +__u8 _ebcasc_500[256] = +{ + /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */ + 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, + /* 0x08 -GE -SPS -RPT VT FF CR SO SI */ + 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC + -ENP ->LF */ + 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, + /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB + -IUS */ + 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC + -INP */ + 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, + /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL + -SW */ + 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, + /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */ + 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, + /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */ + 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, + /* 0x40 SP RSP ---- */ + 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, + /* 0x48 [ . < ( + ! */ + 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, + /* 0x50 & ---- */ + 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, + /* 0x58 ] $ * ) ; ^ */ + 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + /* 0x60 - / ---- ---- ---- ---- */ + 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, + /* 0x68 ---- , % _ > ? */ + 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + /* 0x70 ---- ---- ---- ---- ---- ---- ---- */ + 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + /* 0x78 * ` : # @ ' = " */ + 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + /* 0x80 * a b c d e f g */ + 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + /* 0x88 h i ---- ---- ---- */ + 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, + /* 0x90 j k l m n o p */ + 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + /* 0x98 q r ---- ---- */ + 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, + /* 0xA0 ~ s t u v w x */ + 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + /* 0xA8 y z ---- ---- ---- ---- */ + 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, + /* 0xB0 ---- ---- */ + 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, + /* 0xB8 ---- | ---- ---- ---- ---- */ + 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07, + /* 0xC0 { A B C D E F G */ + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + /* 0xC8 H I ---- ---- */ + 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, + /* 0xD0 } J K L M N O P */ + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + /* 0xD8 Q R ---- */ + 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, + /* 0xE0 \ S T U V W X */ + 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + /* 0xE8 Y Z ---- ---- ---- ---- */ + 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, + /* 0xF0 0 1 2 3 4 5 6 7 */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + /* 0xF8 8 9 ---- ---- ---- ---- ---- */ + 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07 +}; + + +/* + * EBCDIC 037/500 conversion table: * from upper to lower case */ __u8 _ebc_tolower[256] = @@ -202,7 +351,7 @@ /* - * EBCDIC 037 conversion table: + * EBCDIC 037/500 conversion table: * from lower to upper case */ __u8 _ebc_toupper[256] = diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S --- v2.4.1/linux/arch/s390/kernel/entry.S Fri Aug 11 14:29:05 2000 +++ linux/arch/s390/kernel/entry.S Tue Feb 13 14:13:43 2001 @@ -81,6 +81,7 @@ flags = 4 sigpending = 8 need_resched = 24 +tsk_ptrace = 28 processor = 60 /* PSW related defines */ @@ -88,6 +89,13 @@ enable = 0x03 daton = 0x04 +/* + * Base Address of this Module --- saved in __LC_ENTRY_BASE + */ + .globl entry_base +entry_base: + +#define BASED(name) name-entry_base(%r13) #if 0 /* some code left lying around in case we need a @@ -118,39 +126,37 @@ */ #define SAVE_ALL(psworg) \ - st %r15,__LC_SAVE_AREA ; \ + stm %r13,%r15,__LC_SAVE_AREA ; \ + stam %a2,%a4,__LC_SAVE_AREA+12 ; \ + basr %r13,0 ; /* temp base pointer */ \ + l %r13,.Lentry_base-.(%r13) ; /* load &entry_base to %r13 */ \ tm psworg+1,0x01 ; /* test problem state bit */ \ - jz 0f ; /* skip stack setup save */ \ + bz BASED(.+12) ; /* skip stack setup save */ \ l %r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \ -0: ahi %r15,-SP_SIZE ; /* make room for registers & psw */ \ - srl %r15,3 ; \ - sll %r15,3 ; /* align stack pointer to 8 */ \ - stm %r0,%r14,SP_R0(%r15) ; /* store gprs 0-14 to kernel stack */ \ + lam %a2,%a4,BASED(.Lc_ac) ; /* set ac.reg. 2 to primary space */ \ + /* and access reg. 4 to home space */ \ +0: s %r15,BASED(.Lc_spsize); /* make room for registers & psw */ \ + n %r15,BASED(.Lc0xfffffff8) ; /* align stack pointer to 8 */ \ + stm %r0,%r12,SP_R0(%r15) ; /* store gprs 0-12 to kernel stack */ \ st %r2,SP_ORIG_R2(%r15) ; /* store original content of gpr 2 */ \ - mvc SP_RF(4,%r15),__LC_SAVE_AREA ; /* move R15 to stack */ \ + mvc SP_RD(12,%r15),__LC_SAVE_AREA ; /* move R13-R15 to stack */ \ stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */ \ + mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 ; /* store ac. regs */ \ mvc SP_PSW(8,%r15),psworg ; /* move user PSW to stack */ \ - lhi %r0,psworg ; /* store trap indication */ \ + la %r0,psworg ; /* store trap indication */ \ st %r0,SP_TRAP(%r15) ; \ - xc 0(4,%r15),0(%r15) ; /* clear back chain */ \ - tm psworg+1,0x01 ; /* kmod.c .wishes the set_fs & gs */ \ - jz 1f ; /* to work across syscalls */ \ - slr %r0,%r0 ; \ - sar %a2,%r0 ; /* set ac.reg. 2 to primary space */ \ - lhi %r0,1 ; \ - sar %a4,%r0 ; /* set access reg. 4 to home space */ \ -1: + xc 0(4,%r15),0(%r15) ; /* clear back chain */ #define RESTORE_ALL \ - mvc __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ - lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \ - lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ - ni __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \ - lpsw __LC_RETURN_PSW /* back to caller */ + mvc __LC_RETURN_PSW(8),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ + lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \ + lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ + ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \ + lpsw __LC_RETURN_PSW /* back to caller */ #define GET_CURRENT /* load pointer to task_struct to R9 */ \ - lhi %r9,-8192 ; \ - nr %r9,15 + lr %r9,%r15 ; \ + n %r9,BASED(.Lc0xffffe000) /* @@ -162,22 +168,24 @@ */ .globl resume resume: + basr %r1,0 +resume_base: l %r4,_TSS_PTREGS(%r3) tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? - jz RES_DN1 # if not we're fine - stctl %r9,%r11,24(%r15) # We are using per stuff + bz resume_noper-resume_base(%r1) # if not we're fine + stctl %r9,%r11,24(%r15) # We are using per stuff clc _TSS_PER(12,%r3),24(%r15) - je RES_DN1 # we got away without bashing TLB's - lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't -RES_DN1: + be resume_noper-resume_base(%r1) # we got away w/o bashing TLB's + lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't +resume_noper: stm %r6,%r15,24(%r15) # store resume registers of prev task st %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp - lhi %r0,-8192 - nr %r0,%r15 + lr %r0,%r15 + n %r0,.Lc0xffffe000-resume_base(%r1) l %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp - lhi %r1,8191 + l %r1,.Lc8191-resume_base(%r1) or %r1,%r15 - ahi %r1,1 + la %r1,1(%r1) st %r1,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack stam %a2,%a2,_TSS_AR2(%r2) # store kernel access reg. 2 stam %a4,%a4,_TSS_AR4(%r2) # store kernel access reg. 4 @@ -192,38 +200,19 @@ * are executed with interrupts enabled. */ -sysc_lit: - sysc_do_signal: .long do_signal - sysc_do_softirq: .long do_softirq - sysc_schedule: .long schedule - sysc_trace: .long syscall_trace -#ifdef CONFIG_SMP - sysc_schedtail: .long schedule_tail -#endif - sysc_clone: .long sys_clone - sysc_fork: .long sys_fork - sysc_vfork: .long sys_vfork - sysc_sigreturn: .long sys_sigreturn - sysc_rt_sigreturn: .long sys_rt_sigreturn - sysc_execve: .long sys_execve - sysc_sigsuspend: .long sys_sigsuspend - sysc_rt_sigsuspend: .long sys_rt_sigsuspend - .globl system_call system_call: SAVE_ALL(0x20) - XC SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) + xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) pgm_system_call: - basr %r13,0 - ahi %r13,sysc_lit-. # setup base pointer R13 to sysc_lit slr %r8,%r8 # gpr 8 is call save (-> tracesys) ic %r8,0x8B # get svc number from lowcore stosm 24(%r15),0x03 # reenable interrupts GET_CURRENT # load pointer to task_struct to R9 sll %r8,2 - l %r8,sys_call_table-sysc_lit(8,%r13) # get address of system call - tm flags+3(%r9),0x20 # PF_TRACESYS - jnz sysc_tracesys + l %r8,sys_call_table-entry_base(8,%r13) # get address of system call + tm tsk_ptrace+3(%r9),0x02 # PT_TRACESYS + bnz BASED(sysc_tracesys) basr %r14,%r8 # call sys_xxxx st %r2,SP_R2(%r15) # store return value (change R2 on stack) # ATTENTION: check sys_execve_glue before @@ -232,24 +221,24 @@ sysc_return: GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? - jno sysc_leave # no-> skip bottom half, resched & signal + bno BASED(sysc_leave) # no-> skip bottom half, resched & signal # # check, if bottom-half has to be done # l %r0,__LC_IRQ_STAT # get softirq_active n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask - jnz sysc_handle_bottom_half + bnz BASED(sysc_handle_bottom_half) # # check, if reschedule is needed # sysc_return_bh: icm %r0,15,need_resched(%r9) # get need_resched from task_struct - jnz sysc_reschedule + bnz BASED(sysc_reschedule) icm %r0,15,sigpending(%r9) # get sigpending from task_struct - jnz sysc_signal_return + bnz BASED(sysc_signal_return) sysc_leave: icm %r0,15,SP_SVC_STEP(%r15) # get sigpending from task_struct - jnz pgm_svcret + bnz BASED(pgm_svcret) stnsm 24(%r15),disable # disable I/O and ext. interrupts RESTORE_ALL @@ -259,24 +248,24 @@ sysc_signal_return: la %r2,SP_PTREGS(%r15) # load pt_regs sr %r3,%r3 # clear *oldset - l %r1,sysc_do_signal-sysc_lit(%r13) - la %r14,sysc_leave-sysc_lit(%r13) + l %r1,BASED(.Ldo_signal) + la %r14,BASED(sysc_leave) br %r1 # return point is sysc_leave # # call trace before and after sys_call # sysc_tracesys: - l %r1,sysc_trace-sysc_lit(%r13) - lhi %r2,-ENOSYS + l %r1,BASED(.Ltrace) + l %r2,BASED(.Lc_ENOSYS) st %r2,SP_R2(%r15) # give sysc_trace an -ENOSYS retval basr %r14,%r1 lm %r3,%r6,SP_R3(%r15) l %r2,SP_ORIG_R2(%r15) basr %r14,%r8 # call sys_xxx st %r2,SP_R2(%r15) # store return value - l %r1,sysc_trace-sysc_lit(%r13) - la %r14,sysc_return-sysc_lit(%r13) + l %r1,BASED(.Ltrace) + la %r14,BASED(sysc_return) br %r1 # return point is sysc_return @@ -285,16 +274,16 @@ # is zero # sysc_handle_bottom_half: - l %r1,sysc_do_softirq-sysc_lit(%r13) - la %r14,sysc_return_bh-sysc_lit(%r13) + l %r1,BASED(.Ldo_softirq) + la %r14,BASED(sysc_return_bh) br %r1 # call do_softirq # # call schedule with sysc_return as return-address # sysc_reschedule: - l %r1,sysc_schedule-sysc_lit(%r13) - la %r14,sysc_return-sysc_lit(%r13) + l %r1,BASED(.Lschedule) + la %r14,BASED(sysc_return) br %r1 # call scheduler, return to sysc_return # @@ -303,17 +292,17 @@ .globl ret_from_fork ret_from_fork: basr %r13,0 - ahi %r13,sysc_lit-. # setup base pointer R13 to $SYSCDAT + l %r13,.Lentry_base-.(%r13) # setup base pointer to &entry_base GET_CURRENT # load pointer to task_struct to R9 stosm 24(%r15),0x03 # reenable interrupts sr %r0,%r0 # child returns 0 st %r0,SP_R2(%r15) # store return value (change R2 on stack) #ifdef CONFIG_SMP - l %r1,sysc_schedtail-sysc_lit(%r13) - la %r14,sysc_return-sysc_lit(%r13) + l %r1,BASED(.Lschedtail) + la %r14,BASED(sysc_return) br %r1 # call schedule_tail, return to sysc_return #else - j sysc_return + b BASED(sysc_return) #endif # @@ -324,22 +313,22 @@ # sys_clone_glue: la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,sysc_clone-sysc_lit(%r13) + l %r1,BASED(.Lclone) br %r1 # branch to sys_clone sys_fork_glue: la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,sysc_fork-sysc_lit(%r13) + l %r1,BASED(.Lfork) br %r1 # branch to sys_fork sys_vfork_glue: la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,sysc_vfork-sysc_lit(%r13) + l %r1,BASED(.Lvfork) br %r1 # branch to sys_vfork sys_execve_glue: la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,sysc_execve-sysc_lit(%r13) + l %r1,BASED(.Lexecve) lr %r12,%r14 # save return address basr %r14,%r1 # call sys_execve ltr %r2,%r2 # check if execve failed @@ -349,12 +338,12 @@ sys_sigreturn_glue: la %r2,SP_PTREGS(%r15) # load pt_regs as parameter - l %r1,sysc_sigreturn-sysc_lit(%r13) + l %r1,BASED(.Lsigreturn) br %r1 # branch to sys_sigreturn sys_rt_sigreturn_glue: la %r2,SP_PTREGS(%r15) # load pt_regs as parameter - l %r1,sysc_rt_sigreturn-sysc_lit(%r13) + l %r1,BASED(.Lrt_sigreturn) br %r1 # branch to sys_sigreturn # @@ -369,7 +358,7 @@ lr %r4,%r3 # move history1 parameter lr %r3,%r2 # move history0 parameter la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter - l %r1,sysc_sigsuspend-sysc_lit(%r13) + l %r1,BASED(.Lsigsuspend) la %r14,4(%r14) # skip store of return value br %r1 # branch to sys_sigsuspend @@ -377,10 +366,15 @@ lr %r4,%r3 # move sigsetsize parameter lr %r3,%r2 # move unewset parameter la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter - l %r1,sysc_rt_sigsuspend-sysc_lit(%r13) + l %r1,BASED(.Lrt_sigsuspend) la %r14,4(%r14) # skip store of return value br %r1 # branch to sys_rt_sigsuspend +sys_sigaltstack_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + l %r1,BASED(.Lsigaltstack) + br %r1 # branch to sys_sigreturn + .globl sys_call_table sys_call_table: .long sys_ni_syscall /* 0 */ @@ -459,7 +453,7 @@ .long sys_sigpending .long sys_sethostname .long sys_setrlimit /* 75 */ - .long sys_getrlimit + .long sys_old_getrlimit .long sys_getrusage .long sys_gettimeofday .long sys_settimeofday @@ -569,13 +563,13 @@ .long sys_getcwd .long sys_capget .long sys_capset /* 185 */ - .long sys_sigaltstack + .long sys_sigaltstack_glue .long sys_sendfile .long sys_ni_syscall /* streams1 */ .long sys_ni_syscall /* streams2 */ .long sys_vfork_glue /* 190 */ .long sys_getrlimit - .long sys_ni_syscall /* FIXME: problem with sys_mmap2: 6 parms */ + .long sys_mmap2 .long sys_truncate64 .long sys_ftruncate64 .long sys_stat64 /* 195 */ @@ -604,7 +598,8 @@ .long sys_mincore .long sys_madvise .long sys_getdents64 /* 220 */ - .rept 255-220 + .long sys_fcntl64 + .rept 255-221 .long sys_ni_syscall .endr @@ -612,13 +607,6 @@ * Program check handler routine */ -pgm_lit: - pgm_handle_per: .long handle_per_exception - pgm_jump_table: .long pgm_check_table - pgm_sysc_ret: .long sysc_return - pgm_sysc_lit: .long sysc_lit - pgm_do_signal: .long do_signal - .globl pgm_check_handler pgm_check_handler: /* @@ -634,110 +622,131 @@ * we just ignore the PER event (FIXME: is there anything we have to do * for LPSW?). */ + stm %r13,%r15,__LC_SAVE_AREA + stam %a2,%a4,__LC_SAVE_AREA+12 + basr %r13,0 # temp base pointer + l %r13,.Lentry_base-.(%r13)# load &entry_base to %r13 tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception - jz pgm_sv # skip if not + bz BASED(pgm_sv) # skip if not tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on - jnz pgm_sv # skip if it is + bnz BASED(pgm_sv) # skip if it is # ok its one of the special cases, now we need to find out which one clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW - je pgm_svcper + be BASED(pgm_svcper) # no interesting special case, ignore PER event - lpsw 0x28 + lm %r13,%r15,__LC_SAVE_AREA + lpsw 0x28 # it was a single stepped SVC that is causing all the trouble pgm_svcper: - SAVE_ALL(0x20) + tm 0x21,0x01 # test problem state bit + bz BASED(.+12) # skip stack & access regs setup + l %r15,__LC_KERNEL_STACK # problem state -> load ksp + lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space + # and access reg. 4 to home space + s %r15,BASED(.Lc_spsize) # make room for registers & psw + n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 + stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack + st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 + mvc SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack + stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. + mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs + mvc SP_PSW(8,%r15),0x20 # move user PSW to stack + la %r0,0x20 # store trap indication + st %r0,SP_TRAP(%r15) + xc 0(4,%r15),0(%r15) # clear back chain mvi SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information - j pgm_system_call # now do the svc + b BASED(pgm_system_call) # now do the svc pgm_svcret: - lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack - lhi %r0,0x28 - st %r0,SP_TRAP(%r15) # set new trap indicator + mvi SP_TRAP+3(%r15),0x28 # set trap indication back to pgm_chk + lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) - basr %r13,0 - ahi %r13,pgm_lit-. # setup base pointer - j pgm_no_sv + b BASED(pgm_no_sv) pgm_sv: - SAVE_ALL(0x28) - XC SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) - basr %r13,0 - ahi %r13,pgm_lit-. # setup base pointer R13 to $PGMDAT + tm 0x29,0x01 # test problem state bit + bz BASED(.+12) # skip stack & access regs setup + l %r15,__LC_KERNEL_STACK # problem state -> load ksp + lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space + # and access reg. 4 to home space + s %r15,BASED(.Lc_spsize) # make room for registers & psw + n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 + stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack + st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 + mvc SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack + stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. + mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs + mvc SP_PSW(8,%r15),0x28 # move user PSW to stack + la %r0,0x28 # store trap indication + st %r0,SP_TRAP(%r15) + xc 0(4,%r15),0(%r15) # clear back chain + xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) lh %r7,__LC_PGM_ILC # load instruction length pgm_no_sv: lh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it stosm 24(%r15),0x03 # reenable interrupts lr %r3,%r8 - lhi %r0,0x7f + la %r0,0x7f nr %r3,%r0 # clear per-event-bit - je pgm_dn # none of Martins exceptions occured bypass - l %r9,pgm_jump_table-pgm_lit(%r13) + be BASED(pgm_dn) # none of Martins exceptions occured bypass + l %r9,BASED(.Ljump_table) sll %r3,2 l %r9,0(%r3,%r9) # load address of handler routine la %r2,SP_PTREGS(%r15) # address of register-save area srl %r3,2 - chi %r3,0x4 # protection-exception ? - jne pgm_go # if not, + cl %r3,BASED(.Lc4) # protection-exception ? + bne BASED(pgm_go) # if not, l %r5,SP_PSW+4(15) # load psw addr sr %r5,%r7 # substract ilc from psw st %r5,SP_PSW+4(15) # store corrected psw addr pgm_go: basr %r14,%r9 # branch to interrupt-handler -pgm_dn: lhi %r0,0x80 +pgm_dn: la %r0,0x80 nr %r8,%r0 # check for per exception - je pgm_return + be BASED(pgm_return) la %r2,SP_PTREGS(15) # address of register-save area - l %r9,pgm_handle_per-pgm_lit(%r13) # load adr. of per handler - l %r14,pgm_sysc_ret-pgm_lit(%r13) # load adr. of system return - l %r13,pgm_sysc_lit-pgm_lit(%r13) + l %r9,BASED(.Lhandle_per) # load adr. of per handler + la %r14,BASED(sysc_return) # load adr. of system return br %r9 # branch to handle_per_exception + # # the backend code is the same as for sys-call # pgm_return: - l %r14,pgm_sysc_ret-pgm_lit(%r13) - l %r13,pgm_sysc_lit-pgm_lit(%r13) - br %r14 + b BASED(sysc_return) /* * IO interrupt handler routine */ -io_lit: - io_do_IRQ: .long do_IRQ - io_schedule: .long schedule - io_do_signal: .long do_signal - io_do_softirq: .long do_softirq - .globl io_int_handler io_int_handler: SAVE_ALL(0x38) - basr %r13,0 - ahi %r13,io_lit-. # setup base pointer R13 to $IODAT la %r2,SP_PTREGS(%r15) # address of register-save area sr %r3,%r3 icm %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int - l %r4,__LC_IO_INT_PARM # load interuption parm - l %r9,io_do_IRQ-io_lit(%r13) # load address of do_IRQ + l %r4,__LC_IO_INT_PARM # load interruption parm + l %r5,__LC_IO_INT_WORD # load interruption word + l %r9,BASED(.Ldo_IRQ) # load address of do_IRQ basr %r14,%r9 # branch to standard irq handler io_return: GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? - jz io_leave # no-> skip resched & signal + bz BASED(io_leave) # no-> skip resched & signal stosm 24(%r15),0x03 # reenable interrupts # # check, if bottom-half has to be done # l %r0,__LC_IRQ_STAT # get softirq_active n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask - jnz io_handle_bottom_half + bnz BASED(io_handle_bottom_half) io_return_bh: # # check, if reschedule is needed # icm %r0,15,need_resched(%r9) # get need_resched from task_struct - jnz io_reschedule + bnz BASED(io_reschedule) icm %r0,15,sigpending(%r9) # get sigpending from task_struct - jnz io_signal_return + bnz BASED(io_signal_return) io_leave: stnsm 24(%r15),disable # disable I/O and ext. interrupts RESTORE_ALL @@ -747,16 +756,16 @@ # is zero # io_handle_bottom_half: - l %r1,io_do_softirq-io_lit(%r13) - la %r14,io_return_bh-io_lit(%r13) + l %r1,BASED(.Ldo_softirq) + la %r14,BASED(io_return_bh) br %r1 # call do_softirq # # call schedule with io_return as return-address # io_reschedule: - l %r1,io_schedule-io_lit(%r13) - la %r14,io_return-io_lit(%r13) + l %r1,BASED(.Lschedule) + la %r14,BASED(io_return) br %r1 # call scheduler, return to io_return # @@ -765,103 +774,46 @@ io_signal_return: la %r2,SP_PTREGS(%r15) # load pt_regs sr %r3,%r3 # clear *oldset - l %r1,io_do_signal-io_lit(%r13) - la %r14,io_leave-io_lit(%r13) + l %r1,BASED(.Ldo_signal) + la %r14,BASED(io_leave) br %r1 # return point is io_leave /* * External interrupt handler routine */ -ext_lit: - ext_timer_int: .long do_timer_interrupt -#ifdef CONFIG_SMP - ext_call_int: .long do_ext_call_interrupt -#endif -#ifdef CONFIG_HWC - ext_hwc_int: .long do_hwc_interrupt -#endif -#ifdef CONFIG_MDISK - ext_mdisk_int: .long do_mdisk_interrupt -#endif -#ifdef CONFIG_IUCV - ext_iucv_int: .long do_iucv_interrupt -#endif - ext_io_lit: .long io_lit - ext_io_return: .long io_return - .globl ext_int_handler ext_int_handler: SAVE_ALL(0x18) - basr %r13,0 - ahi %r13,ext_lit-. # setup base pointer R13 to $EXTDAT la %r2,SP_PTREGS(%r15) # address of register-save area lh %r3,__LC_EXT_INT_CODE # error code -#ifdef CONFIG_SMP - chi %r3,0x1202 # EXTERNAL_CALL - jne ext_no_extcall - l %r9,ext_call_int-ext_lit(%r13) # load ext_call_interrupt - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r9 # branch to ext call handler -ext_no_extcall: -#endif - chi %r3,0x1004 # CPU_TIMER - jne ext_no_timer - l %r9,ext_timer_int-ext_lit(%r13) # load timer_interrupt - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r9 # branch to ext call handler -ext_no_timer: -#ifdef CONFIG_HWC - chi %r3,0x2401 # HWC interrupt - jne ext_no_hwc - l %r9,ext_hwc_int-ext_lit(%r13) # load addr. of hwc routine - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r9 # branch to ext call handler -ext_no_hwc: -#endif -#ifdef CONFIG_MDISK - chi %r3,0x2603 # diag 250 (VM) interrupt - jne ext_no_mdisk - l %r9,ext_mdisk_int-ext_lit(%r13) - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r9 # branch to ext call handler -ext_no_mdisk: -#endif -#ifdef CONFIG_IUCV - chi %r3,0x4000 # diag 250 (VM) interrupt - jne ext_no_iucv - l %r9,ext_iucv_int-ext_lit(%r13) - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r9 # branch to ext call handler -ext_no_iucv: -#endif - - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r14 # use backend code of io_int_handler + lr %r1,%r3 # calculate index = code & 0xff + n %r1,BASED(.Lc0xff) + sll %r1,2 + l %r9,BASED(.Lext_hash) + l %r9,0(%r1,%r9) # get first list entry for hash value + ltr %r9,%r9 # == NULL ? + bz BASED(io_return) # yes, nothing to do, exit +ext_int_loop: + ch %r3,8(%r9) # compare external interrupt code + be BASED(ext_int_found) + icm %r9,15,0(%r9) # next list entry + bnz BASED(ext_int_loop) + b BASED(io_return) +ext_int_found: + l %r9,4(%r9) # get handler address + la %r14,BASED(io_return) + br %r9 # branch to ext call handler /* * Machine check handler routines */ -mcck_lit: - mcck_crw_pending: .long do_crw_pending - .globl mcck_int_handler mcck_int_handler: SAVE_ALL(0x30) - basr %r13,0 - ahi %r13,mcck_lit-. # setup base pointer R13 to $MCCKDAT - tm __LC_MCCK_CODE+1,0x40 - jno mcck_no_crw - l %r1,mcck_crw_pending-mcck_lit(%r13) - basr %r14,%r1 # call do_crw_pending -mcck_no_crw: + l %r1,BASED(.Ls390_mcck) + basr %r14,%r1 # call machine check handler mcck_return: RESTORE_ALL @@ -876,11 +828,11 @@ lam %a0,%a15,__LC_AREGS_SAVE_AREA stosm 0(%r15),daton # now we can turn dat on lm %r6,%r15,24(%r15) # load registers from clone - bras %r14,restart_go - .long start_secondary -restart_go: - l %r14,0(%r14) + basr %r14,0 + l %r14,restart_addr-.(%r14) br %r14 # branch to start_secondary +restart_addr: + .long start_secondary #else /* * If we do not run with SMP enabled, let the new CPU crash ... @@ -894,5 +846,50 @@ restart_crash: .long 0x000a0000,0x00000000 restart_go: +#endif + +/* + * Integer constants + */ + .align 4 +.Lc0xfffffff8: .long -8 # to align stack pointer to 8 +.Lc0xffffe000: .long -8192 # to round stack pointer to &task_struct +.Lc8191: .long 8191 +.Lc_spsize: .long SP_SIZE +.Lc_ac: .long 0,0,1 +.Lc_ENOSYS: .long -ENOSYS +.Lc4: .long 4 +.Lc0x1202: .long 0x1202 +.Lc0x1004: .long 0x1004 +.Lc0x2401: .long 0x2401 +.Lc0x4000: .long 0x4000 +.Lc0xff: .long 0xff + +/* + * Symbol constants + */ +.Ls390_mcck: .long s390_do_machine_check +.Ldo_IRQ: .long do_IRQ +.Ldo_signal: .long do_signal +.Ldo_softirq: .long do_softirq +.Lentry_base: .long entry_base +.Lext_hash: .long ext_int_hash +.Lhandle_per: .long handle_per_exception +.Ljump_table: .long pgm_check_table +.Lschedule: .long schedule +.Lclone: .long sys_clone +.Lexecve: .long sys_execve +.Lfork: .long sys_fork +.Lrt_sigreturn:.long sys_rt_sigreturn +.Lrt_sigsuspend: + .long sys_rt_sigsuspend +.Lsigreturn: .long sys_sigreturn +.Lsigsuspend: .long sys_sigsuspend +.Lsigaltstack: .long sys_sigaltstack +.Ltrace: .long syscall_trace +.Lvfork: .long sys_vfork + +#ifdef CONFIG_SMP +.Lschedtail: .long schedule_tail #endif diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S --- v2.4.1/linux/arch/s390/kernel/head.S Fri May 12 11:41:44 2000 +++ linux/arch/s390/kernel/head.S Tue Feb 13 14:13:43 2001 @@ -2,20 +2,29 @@ * arch/s390/kernel/head.S * * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Hartmut Penner (hp@de.ibm.com), * Martin Schwidefsky (schwidefsky@de.ibm.com), + * Rob van der Heij (rvdhei@iae.nl) * - * There are 4 different IPL methods + * There are 5 different IPL methods * 1) load the image directly into ram at address 0 and do an PSW restart * 2) linload will load the image from address 0x10000 to memory 0x10000 * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated) * 3) generate the tape ipl header, store the generated image on a tape * and ipl from it + * In case of SL tape you need to IPL 5 times to get past VOL1 etc * 4) generate the vm reader ipl header, move the generated image to the * VM reader (use option NOH!) and do a ipl from reader (VM only) + * 5) direct call of start by the SALIPL loader * We use the cpuid to distinguish between VM and native ipl * params for kernel are pushed to 0x10400 (see setup.h) + + Changes: + Okt 25 2000 + added code to skip HDR and EOF to allow SL tape IPL (5 retries) + changed first CCW from rewind to backspace block + */ #include @@ -24,40 +33,13 @@ #ifndef CONFIG_IPL .org 0 - .long 0x00080000,0x80000000+iplstart # Just a restart PSW - -iplstart: - l %r12,.Lparm # pointer to parameter area -# -# find out memory size -# - mvc 104(8,0),.Lpcmem0 # setup program check handler - slr %r2,%r2 - lhi %r3,1 - sll %r3,20 -.Lloop0: - l %r0,0(%r2) # test page - ar %r2,%r3 # add 1M - jnm .Lloop0 # r1 < 0x80000000 -> loop -.Lchkmem0: - n %r2,.L4malign0 # align to multiples of 4M - st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size - slr %r2,%r2 - st %r2,INITRD_SIZE-PARMAREA(%r12) # null ramdisk - st %r2,INITRD_START-PARMAREA(%r12) - j start - -.Lparm: .long PARMAREA -.L4malign0:.long 0xffc00000 - .align 8 -.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0 - + .long 0x00080000,0x80000000+startup # Just a restart PSW #else #ifdef CONFIG_IPL_TAPE #define IPL_BS 1024 .org 0 .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded - .long 0x07000000,0x60000001 # by ipl to addresses 0-23. + .long 0x27000000,0x60000001 # by ipl to addresses 0-23. .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs). .long 0x00000000,0x00000000 # external old psw .long 0x00000000,0x00000000 # svc old psw @@ -74,92 +56,6 @@ .long 0x00080000,0x80000000+.Lioint # io new psw .org 0x100 -iplstart: - l %r1,0xb8 # load ipl subchannel number - lhi %r2,IPL_BS # load start address - bras %r14,.Lloader # load rest of ipl image - st %r1,__LC_IPLDEV # store ipl device number - l %r12,.Lparm # pointer to parameter area - -# -# find out memory size -# - mvc 104(8,0),.Lpcmem0 # setup program check handler - slr %r2,%r2 - lhi %r3,1 - sll %r3,20 -.Lloop0: - l %r0,0(%r2) # test page - ar %r2,%r3 # add 1M - jnm .Lloop0 # r1 < 0x80000000 -> loop -.Lchkmem0: - n %r2,.L4malign0 # align to multiples of 4M - st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size - c %r2,.Lbigmem # more than 64 MB of memory ? - jl .Lmemok # if yes load ramdisk to 32 MB - mvc INITRD_START-PARMAREA(4,%r12),.Lrdstart -.Lmemok: - -# -# load parameter file from tape -# - l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp - bras %r14,.Lloader # load parameter file - ltr %r2,%r2 # got anything ? - jz .Lnopf - chi %r2,895 - jnh .Lnotrunc - lhi %r2,895 -.Lnotrunc: - l %r4,INITRD_START-PARMAREA(%r12) - la %r5,0(%r4,%r2) - lr %r3,%r2 -.Lidebc: - tm 0(%r5),0x80 # high order bit set ? - jo .Ldocv # yes -> convert from EBCDIC - ahi %r5,-1 - brct %r3,.Lidebc - j .Lnocv -.Ldocv: - l %r3,.Lcvtab - tr 0(256,%r4),0(%r3) # convert parameters to ascii - tr 256(256,%r4),0(%r3) - tr 512(256,%r4),0(%r3) - tr 768(122,%r4),0(%r3) -.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line - mvc 0(256,%r3),0(%r4) - mvc 256(256,%r3),256(%r4) - mvc 512(256,%r3),512(%r4) - mvc 768(122,%r3),768(%r4) - slr %r0,%r0 - j .Lcntlp -.Ldelspc: - ic %r0,0(%r2,%r3) - chi %r0,0x20 # is it a space ? - je .Lcntlp - ahi %r2,1 - j .Leolp -.Lcntlp: - brct %r2,.Ldelspc -.Leolp: - slr %r0,%r0 - stc %r0,0(%r2,%r3) # terminate buffer -.Lnopf: - -# -# load ramdisk from tape -# - l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk - bras %r14,.Lloader # load ramdisk - st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk - ltr %r2,%r2 - jnz .Lrdcont - st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it -.Lrdcont: -# -# everything loaded, go for it -# - j start # # subroutine for loading from tape # Paramters: @@ -173,32 +69,32 @@ lctl %c6,%c6,.Lcr6 slr %r2,%r2 .Lldlp: - lhi %r6,3 # 3 retries + la %r6,3 # 3 retries .Lssch: ssch 0(%r3) # load chunk of IPL_BS bytes - jnz .Llderr + bnz .Llderr .Lw4end: - bras %r14,.Lwait4io + bas %r14,.Lwait4io tm 8(%r5),0x82 # do we have a problem ? - jnz .Lrecov + bnz .Lrecov slr %r7,%r7 icm %r7,3,10(%r5) # get residual count lcr %r7,%r7 - ahi %r7,IPL_BS # IPL_BS-residual=#bytes read + la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read ar %r2,%r7 # add to total size tm 8(%r5),0x01 # found a tape mark ? - jnz .Ldone + bnz .Ldone l %r0,.Lccwread+4 # update CCW data addresses ar %r0,%r7 st %r0,.Lccwread+4 - j .Lldlp + b .Lldlp .Ldone: l %r14,.Lldret br %r14 # r2 contains the total size .Lrecov: - bras %r14,.Lsense # do the sensing - brct %r6,.Lssch # dec. retry count & branch - j .Llderr + bas %r14,.Lsense # do the sensing + bct %r6,.Lssch # dec. retry count & branch + b .Llderr # # Sense subroutine # @@ -206,11 +102,11 @@ st %r14,.Lsnsret la %r7,.Lorbsense ssch 0(%r7) # start sense command - jnz .Llderr - bras %r14,.Lwait4io + bnz .Llderr + bas %r14,.Lwait4io l %r14,.Lsnsret tm 8(%r5),0x82 # do we have a problem ? - jnz .Llderr + bnz .Llderr br %r14 # # Wait for interrupt subroutine @@ -219,13 +115,13 @@ lpsw .Lwaitpsw .Lioint: c %r1,0xb8 # compare subchannel number - jne .Lwait4io + bne .Lwait4io tsch 0(%r5) slr %r0,%r0 tm 8(%r5),0x82 # do we have a problem ? - jnz .Lwtexit + bnz .Lwtexit tm 8(%r5),0x04 # got device end ? - jz .Lwait4io + bz .Lwait4io .Lwtexit: br %r14 .Llderr: @@ -249,18 +145,12 @@ .Lcr6: .long 0xff000000 .align 8 .Lcrash:.long 0x000a0000,0x00000000 -.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0 -.Lparm: .long PARMAREA -.L4malign0:.long 0xffc00000 -.Lbigmem:.long 0x04000000 -.Lrdstart:.long 0x02000000 .Lldret:.long 0 .Lsnsret: .long 0 -.Lcvtab:.long _ebcasc # ebcdic to ascii table - #endif /* CONFIG_IPL_TAPE */ #ifdef CONFIG_IPL_VM +#define IPL_BS 0x730 .org 0 .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded .long 0x02000018,0x60000050 # by ipl to addresses 0-23. @@ -287,103 +177,7 @@ .long 0x02000690,0x60000050 .long 0x020006e0,0x20000050 - .org 0xf0 -iplstart: - l %r1,0xb8 # load ipl subchannel number - lhi %r2,0x730 # load start address - bras %r14,.Lloader # load rest of ipl image - st %r1,__LC_IPLDEV # store ipl device number - l %r12,.Lparm # pointer to parameter area - -# -# find out memory size -# - mvc 104(8,0),.Lpcmem0 # setup program check handler - slr %r2,%r2 - lhi %r3,1 - sll %r3,20 -.Lloop0: - l %r0,0(%r2) # test page - ar %r2,%r3 # add 1M - jnm .Lloop0 # r1 < 0x80000000 -> loop -.Lchkmem0: - n %r2,.L4malign0 # align to multiples of 4M - st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size - c %r2,.Lbigmem # more than 64 MB of memory ? - jl .Lmemok # if yes load ramdisk to 32 MB - mvc INITRD_START-PARMAREA(4,%r12),.Lrdstart -.Lmemok: - -# -# load parameter file from reader -# - l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp - bras %r14,.Lloader # load parameter file - ltr %r2,%r2 # got anything ? - jz .Lnopf - chi %r2,895 - jnh .Lnotrunc - lhi %r2,895 -.Lnotrunc: - l %r4,INITRD_START-PARMAREA(%r12) - la %r5,0(%r4,%r2) - lr %r3,%r2 -.Lidebc: - tm 0(%r5),0x80 # high order bit set ? - jo .Ldocv # yes -> convert from EBCDIC - ahi %r5,-1 - brct %r3,.Lidebc - j .Lnocv -.Ldocv: - l %r3,.Lcvtab - tr 0(256,%r4),0(%r3) # convert parameters to ascii - tr 256(256,%r4),0(%r3) - tr 512(256,%r4),0(%r3) - tr 768(122,%r4),0(%r3) -.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line - mvc 0(256,%r3),0(%r4) - mvc 256(256,%r3),256(%r4) - mvc 512(256,%r3),512(%r4) - mvc 768(122,%r3),768(%r4) - slr %r0,%r0 - j .Lcntlp -.Ldelspc: - ic %r0,0(%r2,%r3) - chi %r0,0x20 # is it a space ? - je .Lcntlp - ahi %r2,1 - j .Leolp -.Lcntlp: - brct %r2,.Ldelspc -.Leolp: - slr %r0,%r0 - stc %r0,0(%r2,%r3) # terminate buffer -.Lnopf: - -# -# load ramdisk from reader -# - l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk - bras %r14,.Lloader # load ramdisk - st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk - ltr %r2,%r2 - jnz .Lrdcont - st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it -.Lrdcont: - -# -# everything loaded, reset files in reader, then go for it -# - stidp __LC_CPUID # store cpuid - lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on P/390 ? - je start # no -> skip reset - la %r2,.Lreset - lhi %r3,26 - .long 0x83230008 - j start - # # subroutine for loading cards from the reader # @@ -394,29 +188,29 @@ la %r7,20 .Linit: st %r2,4(%r6) # initialize CCW data addresses - ahi %r2,0x50 - ahi %r6,8 - brct 7,.Linit + la %r2,0x50(%r2) + la %r6,8(%r6) + bct 7,.Linit lctl %c6,%c6,.Lcr6 # set IO subclass mask slr %r2,%r2 .Lldlp: ssch 0(%r3) # load chunk of 1600 bytes - jnz .Llderr + bnz .Llderr .Lwait4irq: mvc __LC_IO_NEW_PSW(8),.Lnewpsw # set up IO interrupt psw lpsw .Lwaitpsw .Lioint: c %r1,0xb8 # compare subchannel number - jne .Lwait4irq + bne .Lwait4irq tsch 0(%r5) slr %r0,%r0 ic %r0,8(%r5) # get device status chi %r0,8 # channel end ? - je .Lcont + be .Lcont chi %r0,12 # channel end + device end ? - je .Lcont + be .Lcont l %r0,4(%r5) s %r0,8(%r3) # r0/8 = number of ccws executed @@ -436,9 +230,9 @@ ahi %r0,0x640 st %r0,4(%r6) ahi %r6,8 - brct 7,.Lincr + bct 7,.Lincr - j .Lldlp + b .Lldlp .Llderr: lpsw .Lcrash @@ -447,16 +241,7 @@ .Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .Lcr6: .long 0xff000000 .Lloadp:.long 0,0 -.Lparm: .long PARMAREA -.L4malign0:.long 0xffc00000 -.Lbigmem:.long 0x04000000 -.Lrdstart:.long 0x02000000 -.Lcvtab:.long _ebcasc # ebcdic to ascii table -.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40 - .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6 - .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" .align 8 -.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0 .Lcrash:.long 0x000a0000,0x00000000 .Lnewpsw: .long 0x00080000,0x80000000+.Lioint @@ -468,79 +253,330 @@ .long 0x02600050,0x00000000 .endr .long 0x02200050,0x00000000 - - .org 0x730 # end of the area loaded by the ipl channel program #endif /* CONFIG_IPL_VM */ +iplstart: + lh %r1,0xb8 # test if subchannel number + bct %r1,.Lnoload # is valid + l %r1,0xb8 # load ipl subchannel number + la %r2,IPL_BS # load start address + bas %r14,.Lloader # load rest of ipl image + st %r1,__LC_IPLDEV # store ipl device number + l %r12,.Lparm # pointer to parameter area + +# +# load parameter file from ipl device +# +.Lagain1: + l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp + bas %r14,.Lloader # load parameter file + ltr %r2,%r2 # got anything ? + bz .Lnopf + chi %r2,895 + bnh .Lnotrunc + la %r2,895 +.Lnotrunc: + l %r4,INITRD_START-PARMAREA(%r12) + clc 0(3,%r4),.L_hdr # if it is HDRx + bz .Lagain1 # skip dataset header + clc 0(3,%r4),.L_eof # if it is EOFx + bz .Lagain1 # skip dateset trailer + la %r5,0(%r4,%r2) + lr %r3,%r2 +.Lidebc: + tm 0(%r5),0x80 # high order bit set ? + bo .Ldocv # yes -> convert from EBCDIC + ahi %r5,-1 + bct %r3,.Lidebc + b .Lnocv +.Ldocv: + l %r3,.Lcvtab + tr 0(256,%r4),0(%r3) # convert parameters to ascii + tr 256(256,%r4),0(%r3) + tr 512(256,%r4),0(%r3) + tr 768(122,%r4),0(%r3) +.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line + mvc 0(256,%r3),0(%r4) + mvc 256(256,%r3),256(%r4) + mvc 512(256,%r3),512(%r4) + mvc 768(122,%r3),768(%r4) + slr %r0,%r0 + b .Lcntlp +.Ldelspc: + ic %r0,0(%r2,%r3) + chi %r0,0x20 # is it a space ? + be .Lcntlp + ahi %r2,1 + b .Leolp +.Lcntlp: + brct %r2,.Ldelspc +.Leolp: + slr %r0,%r0 + stc %r0,0(%r2,%r3) # terminate buffer +.Lnopf: + +# +# load ramdisk from ipl device +# +.Lagain2: + l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk + bas %r14,.Lloader # load ramdisk + st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk + ltr %r2,%r2 + bnz .Lrdcont + st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it +.Lrdcont: + l %r2,INITRD_START-PARMAREA(%r12) + + clc 0(3,%r2),.L_hdr # skip HDRx and EOFx + bz .Lagain2 + clc 0(3,%r2),.L_eof + bz .Lagain2 + +#ifdef CONFIG_IPL_VM +# +# reset files in VM reader +# + stidp __LC_CPUID # store cpuid + lh %r0,__LC_CPUID+4 # get cpu version + chi %r0,0x7490 # running on P/390 ? + be start # no -> skip reset + la %r2,.Lreset + lhi %r3,26 + .long 0x83230008 +#endif + +# +# everything loaded, go for it +# +.Lnoload: + l %r1,.Lstartup + br %r1 + +.Lparm: .long PARMAREA +.Lstartup: .long startup +.Lcvtab:.long _ebcasc # ebcdic to ascii table +.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40 + .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6 + .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" +.L_eof: .long 0xc5d6c600 /* C'EOF' */ +.L_hdr: .long 0xc8c4d900 /* C'HDR' */ + #endif /* CONFIG_IPL */ # +# SALIPL loader support. Based on a patch by Rob van der Heij. +# This entry point is called directly from the SALIPL loader and +# doesn't need a builtin ipl record. +# + .org 0x800 + .globl start +start: + stm %r0,%r15,0x07b0 # store registers + basr %r12,%r0 +.base: + l %r11,.parm + l %r8,.cmd # pointer to command buffer + + ltr %r9,%r9 # do we have SALIPL parameters? + bp .sk8x8 + + mvc 0(64,%r8),0x00b0 # copy saved registers + xc 64(240-64,%r8),0(%r8) # remainder of buffer + tr 0(64,%r8),.lowcase + b .gotr +.sk8x8: + mvc 0(240,%r8),0(%r9) # copy iplparms into buffer +.gotr: + l %r10,.tbl # EBCDIC to ASCII table + tr 0(240,%r8),0(%r10) + stidp __LC_CPUID # Are we running on VM maybe + cli __LC_CPUID,0xff + bnz .test + .long 0x83300060 # diag 3,0,x'0060' - storage size + b .done +.test: + mvc 0x68(8),.pgmnw # set up pgm check handler + l %r2,.fourmeg + lr %r3,%r2 + bctr %r3,%r0 # 4M-1 +.loop: iske %r0,%r3 + ar %r3,%r2 +.pgmx: + sr %r3,%r2 + la %r3,1(%r3) +.done: + st %r3,MEMORY_SIZE-PARMAREA(%r11) + slr %r0,%r0 + st %r0,INITRD_SIZE-PARMAREA(%r11) + st %r0,INITRD_START-PARMAREA(%r11) + j startup # continue with startup +.tbl: .long _ebcasc # translate table +.cmd: .long COMMAND_LINE # address of command line buffer +.parm: .long PARMAREA +.fourmeg: .long 0x00400000 # 4M +.pgmnw: .long 0x00080000,.pgmx +.lowcase: + .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 + .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 + .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f + .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 + .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f + .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37 + .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f + .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47 + .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f + .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57 + .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f + .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67 + .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f + .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77 + .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f + + .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87 + .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f + .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97 + .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f + .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 + .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf + .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7 + .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf + .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg + .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi + .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop + .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr + .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx + .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz + .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7 + .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff + +# # startup-code at 0x10000, running in real mode -# this is called either by the ipl loader or directly by PSW restart or linload +# this is called either by the ipl loader or directly by PSW restart +# or linload or SALIPL # .org 0x10000 - .globl start -start: basr %r13,0 # get base -.LPG1: lctl %c1,%c1,.Lpstd-.LPG1(%r13) # load pstd - lctl %c7,%c7,.Lpstd-.LPG1(%r13) # load sstd - lctl %c13,%c13,.Lpstd-.LPG1(%r13) # load hstd - lctl %c0,%c0,.Lcr0-.LPG1(%r13) # set CR0 +startup:basr %r13,0 # get base +.LPG1: lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers l %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area # -# find out memory size. That is done in the ipl loader too but for -# ipl from dasd the size of the memory has to be detected too... +# find out memory size. # - icm %r0,15,MEMORY_SIZE-PARMAREA(%r12) - jnz .Lsizeok - mvc 104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler - slr %r1,%r1 + mvc 104(8),.Lpcmem-.LPG1(%r13) # setup program check handler lhi %r2,1 - sll %r2,20 + sll %r2,17 # test in increments of 128KB + lr %r1,%r2 + ahi %r1,-4 # test last word in the segment .Lloop: - l %r0,0(%r1) # test page - ar %r1,%r2 # add 1M - jnm .Lloop # r1 < 0x80000000 -> loop + l %r0,0(%r1) # test 128KB segment + st %r0,0(%r1) + ar %r1,%r2 # add 128KB + bnm .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop .Lchkmem: n %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M st %r1,MEMORY_SIZE-PARMAREA(%r12) # store memory size .Lsizeok: # +# Now we have to move the ramdisk to a location approriate for the +# memory size. If we have more than 64 MB of memory we move it to 32MB +# to make room for the page tables set up by paging_init. +# + l %r1,MEMORY_SIZE-PARMAREA(%r12) + cl %r1,.Lbigmem-.LPG1(%r13) # memory < 64mb ? + bl .Lnomove-.LPG1(%r13) # if yes ramdisk @8MB is ok + icm %r4,15,INITRD_START-PARMAREA(%r12) + bz .Lnomove-.LPG1(%r13) + l %r2,.Lrdstart-.LPG1(%r13) # new address of ramdisk + st %r2,INITRD_START-PARMAREA(%r12) + l %r1,INITRD_SIZE-PARMAREA(%r12) + ar %r2,%r1 # we start moving at the end + ar %r4,%r1 # because new location > old location +.Lmove: lr %r0,%r2 # new - old is the maximum we can move + sr %r0,%r4 # because of overlapping + cr %r0,%r1 # we shouldn't move more than there is + bnh .Lnoend-.LPG1(%r13) + lr %r0,%r1 +.Lnoend:cl %r0,.Lmaxchunk-.LPG1(%r13) # mvcl can move 2^24-1 in one go + bnh .Lchunk-.LPG1(%r13) + l %r0,.Lmaxchunk-.LPG1(%r13) +.Lchunk:sr %r2,%r0 # make source & destination pointer + sr %r4,%r0 + lr %r3,%r0 # set source & destination length + lr %r5,%r0 + mvcl %r2,%r4 + sr %r2,%r0 # substract length again, since + sr %r4,%r0 # mvcl added it to the pointers + sr %r1,%r0 # substract chunk size from length + bnz .Lmove-.LPG1(%r13) +.Lnomove: + +# # find out if we are running under VM # stidp __LC_CPUID # store cpuid tm __LC_CPUID,0xff # running under VM ? - jno .Lnovm + bno .Lnovm-.LPG1(%r13) oi MACHINE_FLAGS+3-PARMAREA(%r12),1 # set VM flag .Lnovm: lh %r0,__LC_CPUID+4 # get cpu version chi %r0,0x7490 # running on a P/390 ? - jne .Lnop390 + bne .Lnop390-.LPG1(%r13) oi MACHINE_FLAGS+3-PARMAREA(%r12),4 # set P/390 flag .Lnop390: # # find out if we have an IEEE fpu # - mvc 104(8,0),.Lpcfpu-.LPG1(%r13) # setup program check handler + mvc 104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0 ldr %f2,%f0 adbr %f0,%f2 # test IEEE add instruction oi MACHINE_FLAGS+3-PARMAREA(%r12),2 # set IEEE fpu flag .Lchkfpu: +# +# find out if we have the CSP instruction +# + mvc 104(8),.Lpccsp-.LPG1(%r13) # setup program check handler + la %r0,0 + lr %r1,%r0 + la %r2,.Lflt0-.LPG1(%r13) + csp %r0,%r2 # Test CSP instruction + oi MACHINE_FLAGS+3-PARMAREA(%r12),8 # set CSP flag +.Lchkcsp: + lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space, # virtual and never return ... .align 8 -.Lentry:.long 0x04080000,0x80000000 + _stext -.Lpstd: .long .Lpgd+0x7F # segment-table -.Lcr0: .long 0x04b50002 +.Lentry:.long 0x00080000,0x80000000 + _stext +.Lctl: .long 0x04b50002 # cr0: various things + .long 0 # cr1: primary space segment table + .long 0 # cr2: access register translation + .long 0 # cr3: instruction authorization + .long 0 # cr4: instruction authorization + .long 0 # cr5: various things + .long 0 # cr6: I/O interrupts + .long 0 # cr7: secondary space segment table + .long 0 # cr8: access registers translation + .long 0 # cr9: tracing off + .long 0 # cr10: tracing off + .long 0 # cr11: tracing off + .long 0 # cr12: tracing off + .long 0 # cr13: home space segment table + .long 0xc0000000 # cr14: machine check handling off + .long 0 # cr15: linkage stack operations .Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem .Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu +.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp .Lflt0: .double 0 .Lparm1:.long PARMAREA .L4malign:.long 0xffc00000 +.Lbigmem:.long 0x04000000 +.Lrdstart:.long 0x02000000 +.Lmaxchunk:.long 0x00ffffff # # params at 10400 (setup.h) @@ -555,17 +591,8 @@ .word 0 # RAMDISK_FLAGS .org COMMAND_LINE -# .byte "root=/dev/nfs rw nfsroot=9.164.160.7:/home/mschwide/nfsboot " -# .byte "ip=9.164.147.12:9.164.160.7:9.164.147.1:255.255.255.0:vmlinux:tr0:off" -# .byte "root=/dev/nfs nfsroot=9.164.160.7:/home/mschwide/nfsboot " -# .byte "ip=9.164.181.228:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off" -# .byte "root=/dev/nfs nfsroot=9.164.160.7:/home/pasch/nfsboot " -# .byte "ip=9.164.185.120:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off" -# .byte "mdisk=402:65536:1229,403:131072:2780 root=/dev/mnda ro" -# .byte "root=/dev/nfs rw nfsroot=9.164.160.209:/usr/local/nfsboot " -# .byte "ip=9.164.181.228:9.164.160.209:9.164.181.1:255.255.224.0:vmlinux:tr0:off" .byte "root=/dev/ram0 ro" -# .byte 0 + .byte 0 # # startup-code, running in virtual mode @@ -625,44 +652,4 @@ .Laregs: .long 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 .align 8 .Ldw: .long 0x000a0000,0x00000000 - -# -# tempory segment-table at 0x11000 -# - .org 0x11000 -.Lpgd: .long .Lpt0+0x1f # 00000000-000fffff - .long .Lpt1+0x1f # 00100000-001fffff - .long .Lpt2+0x1f # 00200000-002fffff - .long .Lpt3+0x1f # 00300000-003fffff - .fill 2044,4,0x20 # 00400000-7fffffff - -# -# tempory page-tables at 0x12000-0x15fff -# - .macro mktable from,to - .long \from*0x10000 - .long \from*0x10000+0x1000 - .long \from*0x10000+0x2000 - .long \from*0x10000+0x3000 - .long \from*0x10000+0x4000 - .long \from*0x10000+0x5000 - .long \from*0x10000+0x6000 - .long \from*0x10000+0x7000 - .long \from*0x10000+0x8000 - .long \from*0x10000+0x9000 - .long \from*0x10000+0xa000 - .long \from*0x10000+0xb000 - .long \from*0x10000+0xc000 - .long \from*0x10000+0xd000 - .long \from*0x10000+0xe000 - .long \from*0x10000+0xf000 - .if \to-\from - mktable "(\from+1)",\to - .endif - .endm - -.Lpt0: mktable 0,15 -.Lpt1: mktable 16,31 -.Lpt2: mktable 32,47 -.Lpt3: mktable 48,63 diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c --- v2.4.1/linux/arch/s390/kernel/irq.c Fri Aug 4 16:15:37 2000 +++ linux/arch/s390/kernel/irq.c Tue Feb 13 14:13:43 2001 @@ -20,11 +20,11 @@ #include #include #include -#include +#include #include #include #include -#include +#include #include #include @@ -205,6 +205,8 @@ if (!local_bh_count(cpu) && atomic_read(&global_bh_count)) continue; + /* this works even though global_irq_lock not + a long, but is arch-specific --RR */ if (!test_and_set_bit(0,&global_irq_lock)) break; } @@ -243,6 +245,8 @@ static inline void get_irqlock(int cpu) { + /* this works even though global_irq_lock not a long, but is + arch-specific --RR */ if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ if ( cpu == atomic_read(&global_irq_holder)) @@ -398,7 +402,7 @@ void __init init_IRQ(void) { - s390_init_IRQ(); + s390_init_IRQ(); } diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/mathemu.c linux/arch/s390/kernel/mathemu.c --- v2.4.1/linux/arch/s390/kernel/mathemu.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/kernel/mathemu.c Tue Feb 13 14:13:43 2001 @@ -9,6 +9,7 @@ * that does not have the IEEE fpu */ +#include #include #include #include @@ -16,7 +17,59 @@ #include #include -static void set_CC_df(__u64 val1,__u64 val2) { +#ifdef CONFIG_SYSCTL +int sysctl_ieee_emulation_warnings=1; +#endif + +#define mathemu_put_user(x, ptr) \ +{ \ + if(put_user((x),(ptr))) \ + return 1; \ +} + +#define mathemu_get_user(x, ptr) \ +{ \ + if(get_user((x),(ptr))) \ + return 1; \ +} + + +#define mathemu_copy_from_user(to,from,n) \ +{ \ + if(copy_from_user((to),(from),(n))==-EFAULT) \ + return 1; \ +} + + +#define mathemu_copy_to_user(to, from, n) \ +{ \ + if(copy_to_user((to),(from),(n))==-EFAULT) \ + return 1; \ +} + + + +static void display_emulation_not_implemented(char *instr) +{ + struct pt_regs *regs; + __u16 *location; + +#if CONFIG_SYSCTL + if(sysctl_ieee_emulation_warnings) +#endif + { + regs=current->thread.regs; + location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n", + instr, + current->comm, current->pid); + printk("%s's PSW: %08lx %08lx\n",instr, + (unsigned long) regs->psw.mask, + (unsigned long) location); + } +} + +static int set_CC_df(__u64 val1,__u64 val2) { int rc; rc = __cmpdf2(val1,val2); current->thread.regs->psw.mask &= 0xFFFFCFFF; @@ -28,9 +81,10 @@ current->thread.regs->psw.mask |= 0x00002000; break; } + return 0; } -static void set_CC_sf(__u32 val1,__u32 val2) { +static int set_CC_sf(__u32 val1,__u32 val2) { int rc; rc = __cmpsf2(val1,val2); current->thread.regs->psw.mask &= 0xFFFFCFFF; @@ -42,384 +96,473 @@ current->thread.regs->psw.mask |= 0x00002000; break; } + return 0; } -static void emu_adb (int rx, __u64 val) { +static int emu_adb (int rx, __u64 val) { current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,val); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_adbr (int rx, int ry) { +static int emu_adbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d, current->thread.fp_regs.fprs[ry].d); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_aeb (int rx, __u32 val) { +static int emu_aeb (int rx, __u32 val) { current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,val); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_aebr (int rx, int ry) { +static int emu_aebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f, current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_axbr (int rx, int ry) { - printk("axbr emulation not implemented!\n"); +static int emu_axbr (int rx, int ry) { + display_emulation_not_implemented("axbr"); + return 0; } -static void emu_cdb (int rx, __u64 val) { +static int emu_cdb (int rx, __u64 val) { set_CC_df(current->thread.fp_regs.fprs[rx].d,val); + return 0; } -static void emu_cdbr (int rx, int ry) { +static int emu_cdbr (int rx, int ry) { set_CC_df(current->thread.fp_regs.fprs[rx].d,current->thread.fp_regs.fprs[ry].d); + return 0; } -static void emu_cdfbr (int rx, int ry) { +static int emu_cdfbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __floatsidf(current->thread.regs->gprs[ry]); + return 0; } -static void emu_ceb (int rx, __u32 val) { +static int emu_ceb (int rx, __u32 val) { set_CC_sf(current->thread.fp_regs.fprs[rx].f,val); + return 0; } -static void emu_cebr (int rx, int ry) { +static int emu_cebr (int rx, int ry) { set_CC_sf(current->thread.fp_regs.fprs[rx].f,current->thread.fp_regs.fprs[ry].f); + return 0; } -static void emu_cefbr (int rx, int ry) { +static int emu_cefbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __floatsisf(current->thread.regs->gprs[ry]); + return 0; } -static void emu_cfdbr (int rx, int ry, int mask) { +static int emu_cfdbr (int rx, int ry, int mask) { current->thread.regs->gprs[rx] = __fixdfsi(current->thread.fp_regs.fprs[ry].d); + return 0; } -static void emu_cfebr (int rx, int ry, int mask) { +static int emu_cfebr (int rx, int ry, int mask) { current->thread.regs->gprs[rx] = __fixsfsi(current->thread.fp_regs.fprs[ry].f); + return 0; } -static void emu_cfxbr (int rx, int ry, int mask) { - printk("cfxbr emulation not implemented!\n"); +static int emu_cfxbr (int rx, int ry, int mask) { + display_emulation_not_implemented("cfxbr"); + return 0; } -static void emu_cxbr (int rx, int ry) { - printk("cxbr emulation not implemented!\n"); +static int emu_cxbr (int rx, int ry) { + display_emulation_not_implemented("cxbr"); + return 0; } -static void emu_cxfbr (int rx, int ry) { - printk("cxfbr emulation not implemented!\n"); +static int emu_cxfbr (int rx, int ry) { + display_emulation_not_implemented("cxfbr"); + return 0; } -static void emu_ddb (int rx, __u64 val) { +static int emu_ddb (int rx, __u64 val) { current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,val); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_ddbr (int rx, int ry) { +static int emu_ddbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d, current->thread.fp_regs.fprs[ry].d); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_deb (int rx, __u32 val) { +static int emu_deb (int rx, __u32 val) { current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,val); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_debr (int rx, int ry) { +static int emu_debr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f, current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_didbr (int rx, int ry, int mask) { - printk("didbr emulation not implemented!\n"); +static int emu_didbr (int rx, int ry, int mask) { + display_emulation_not_implemented("didbr"); + return 0; } -static void emu_diebr (int rx, int ry, int mask) { - printk("diebr emulation not implemented!\n"); +static int emu_diebr (int rx, int ry, int mask) { + display_emulation_not_implemented("diebr"); + return 0; } -static void emu_dxbr (int rx, int ry) { - printk("dxbr emulation not implemented!\n"); +static int emu_dxbr (int rx, int ry) { + display_emulation_not_implemented("dxbr"); + return 0; } -static void emu_efpc (int rx, int ry) { - printk("efpc emulation not implemented!\n"); +static int emu_efpc (int rx, int ry) { + current->thread.regs->gprs[rx]=current->thread.fp_regs.fpc; + return 0; } -static void emu_fidbr (int rx, int ry, int mask) { - printk("fidbr emulation not implemented!\n"); +static int emu_fidbr (int rx, int ry, int mask) { + display_emulation_not_implemented("fidbr"); + return 0; } -static void emu_fiebr (int rx, int ry, int mask) { - printk("fiebr emulation not implemented!\n"); +static int emu_fiebr (int rx, int ry, int mask) { + display_emulation_not_implemented("fiebr"); + return 0; } -static void emu_fixbr (int rx, int ry, int mask) { - printk("fixbr emulation not implemented!\n"); +static int emu_fixbr (int rx, int ry, int mask) { + display_emulation_not_implemented("fixbr"); + return 0; } -static void emu_kdb (int rx, __u64 val) { - printk("kdb emulation not implemented!\n"); +static int emu_kdb (int rx, __u64 val) { + display_emulation_not_implemented("kdb"); + return 0; } -static void emu_kdbr (int rx, int ry) { - printk("kdbr emulation not implemented!\n"); +static int emu_kdbr (int rx, int ry) { + display_emulation_not_implemented("kdbr"); + return 0; } -static void emu_keb (int rx, __u32 val) { - printk("keb emulation not implemented!\n"); +static int emu_keb (int rx, __u32 val) { + display_emulation_not_implemented("keb"); + return 0; } -static void emu_kebr (int rx, int ry) { - printk("kebr emulation not implemented!\n"); +static int emu_kebr (int rx, int ry) { + display_emulation_not_implemented("kebr"); + return 0; } -static void emu_kxbr (int rx, int ry) { - printk("kxbr emulation not implemented!\n"); +static int emu_kxbr (int rx, int ry) { + display_emulation_not_implemented("kxbr"); + return 0; } -static void emu_lcdbr (int rx, int ry) { +static int emu_lcdbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __negdf2(current->thread.fp_regs.fprs[ry].d); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_lcebr (int rx, int ry) { +static int emu_lcebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __negsf2(current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lcxbr (int rx, int ry) { - printk("lcxbr emulation not implemented!\n"); +static int emu_lcxbr (int rx, int ry) { + display_emulation_not_implemented("lcxbr"); + return 0; } -static void emu_ldeb (int rx, __u32 val) { +static int emu_ldeb (int rx, __u32 val) { current->thread.fp_regs.fprs[rx].d = __extendsfdf2(val); + return 0; } -static void emu_ldebr (int rx, int ry) { +static int emu_ldebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __extendsfdf2(current->thread.fp_regs.fprs[ry].f); + return 0; } -static void emu_ldxbr (int rx, int ry) { - printk("ldxbr emulation not implemented!\n"); +static int emu_ldxbr (int rx, int ry) { + display_emulation_not_implemented("ldxbr"); + return 0; } -static void emu_ledbr (int rx, int ry) { +static int emu_ledbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __truncdfsf2(current->thread.fp_regs.fprs[ry].d); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lexbr (int rx, int ry) { - printk("lexbr emulation not implemented!\n"); +static int emu_lexbr (int rx, int ry) { + display_emulation_not_implemented("lexbr"); + return 0; } -static void emu_lndbr (int rx, int ry) { - printk("lndbr emulation not implemented!\n"); +static int emu_lndbr (int rx, int ry) { + display_emulation_not_implemented("lndbr"); + return 0; } -static void emu_lnebr (int rx, int ry) { - printk("lnebr emulation not implemented!\n"); +static int emu_lnebr (int rx, int ry) { + display_emulation_not_implemented("lnebr"); + return 0; } -static void emu_lnxbr (int rx, int ry) { - printk("lnxbr emulation not implemented!\n"); +static int emu_lnxbr (int rx, int ry) { + display_emulation_not_implemented("lnxbr"); + return 0; } -static void emu_lpdbr (int rx, int ry) { +static int emu_lpdbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __absdf2(current->thread.fp_regs.fprs[ry].d); set_CC_df(current->thread.fp_regs.fprs[rx].d,0); + return 0; } -static void emu_lpebr (int rx, int ry) { +static int emu_lpebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __abssf2(current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lpxbr (int rx, int ry) { - printk("lpxbr emulation not implemented!\n"); +static int emu_lpxbr (int rx, int ry) { + display_emulation_not_implemented("lpxbr"); + return 0; } -static void emu_ltdbr (int rx, int ry) { +static int emu_ltdbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = current->thread.fp_regs.fprs[ry].d; set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_ltebr (int rx, int ry) { +static int emu_ltebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = current->thread.fp_regs.fprs[ry].f; set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_ltxbr (int rx, int ry) { - printk("ltxbr emulation not implemented!\n"); +static int emu_ltxbr (int rx, int ry) { + display_emulation_not_implemented("ltxbr"); + return 0; } -static void emu_lxdb (int rx, __u64 val) { - printk("lxdb emulation not implemented!\n"); +static int emu_lxdb (int rx, __u64 val) { + display_emulation_not_implemented("lxdb"); + return 0; } -static void emu_lxdbr (int rx, int ry) { - printk("lxdbr emulation not implemented!\n"); +static int emu_lxdbr (int rx, int ry) { + display_emulation_not_implemented("lxdbr"); + return 0; } -static void emu_lxeb (int rx, __u32 val) { - printk("lxeb emulation not implemented!\n"); +static int emu_lxeb (int rx, __u32 val) { + display_emulation_not_implemented("lxeb"); + return 0; } -static void emu_lxebr (int rx, int ry) { - printk("lxebr emulation not implemented!\n"); +static int emu_lxebr (int rx, int ry) { + display_emulation_not_implemented("lxebr"); + return 0; } -static void emu_madb (int rx, __u64 val, int mask) { - printk("madb emulation not implemented!\n"); +static int emu_madb (int rx, __u64 val, int mask) { + display_emulation_not_implemented("madb"); + return 0; } -static void emu_madbr (int rx, int ry, int mask) { - printk(" emulation not implemented!\n"); +static int emu_madbr (int rx, int ry, int mask) { + display_emulation_not_implemented("madbr"); + return 0; } -static void emu_maeb (int rx, __u32 val, int mask) { - printk("maeb emulation not implemented!\n"); +static int emu_maeb (int rx, __u32 val, int mask) { + display_emulation_not_implemented("maeb"); + return 0; } -static void emu_maebr (int rx, int ry, int mask) { - printk("maebr emulation not implemented!\n"); +static int emu_maebr (int rx, int ry, int mask) { + display_emulation_not_implemented("maebr"); + return 0; } -static void emu_mdb (int rx, __u64 val) { +static int emu_mdb (int rx, __u64 val) { current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,val); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_mdbr (int rx, int ry) { +static int emu_mdbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d, current->thread.fp_regs.fprs[ry].d); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_mdeb (int rx, __u32 val) { - printk("mdeb emulation not implemented!\n"); +static int emu_mdeb (int rx, __u32 val) { + display_emulation_not_implemented("mdeb"); + return 0; } -static void emu_mdebr (int rx, int ry) { - printk("mdebr emulation not implemented!\n"); +static int emu_mdebr (int rx, int ry) { + display_emulation_not_implemented("mdebr"); + return 0; } -static void emu_meeb (int rx, __u32 val) { +static int emu_meeb (int rx, __u32 val) { current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f, val); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_meebr (int rx, int ry) { +static int emu_meebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f, current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_msdb (int rx, __u64 val, int mask) { - printk("msdb emulation not implemented!\n"); +static int emu_msdb (int rx, __u64 val, int mask) { + display_emulation_not_implemented("msdb"); + return 0; } -static void emu_msdbr (int rx, int ry, int mask) { - printk("msdbr emulation not implemented!\n"); +static int emu_msdbr (int rx, int ry, int mask) { + display_emulation_not_implemented("msdbr"); + return 0; } -static void emu_mseb (int rx, __u32 val, int mask) { - printk("mseb emulation not implemented!\n"); +static int emu_mseb (int rx, __u32 val, int mask) { + display_emulation_not_implemented("mseb"); + return 0; } -static void emu_msebr (int rx, int ry, int mask) { - printk("msebr emulation not implemented!\n"); +static int emu_msebr (int rx, int ry, int mask) { + display_emulation_not_implemented("msebr"); + return 0; } -static void emu_mxbr (int rx, int ry) { - printk("mxbr emulation not implemented!\n"); +static int emu_mxbr (int rx, int ry) { + display_emulation_not_implemented("mxbr"); + return 0; } -static void emu_mxdb (int rx, __u64 val) { - printk("mxdb emulation not implemented!\n"); +static int emu_mxdb (int rx, __u64 val) { + display_emulation_not_implemented("mxdb"); + return 0; } -static void emu_mxdbr (int rx, int ry) { - printk("mxdbr emulation not implemented!\n"); +static int emu_mxdbr (int rx, int ry) { + display_emulation_not_implemented("mxdbr"); + return 0; } -static void emu_sdb (int rx, __u64 val) { +static int emu_sdb (int rx, __u64 val) { current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d, val); set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_sdbr (int rx, int ry) { +static int emu_sdbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d, current->thread.fp_regs.fprs[ry].d); set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_seb (int rx, __u32 val) { +static int emu_seb (int rx, __u32 val) { current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f, val); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_sebr (int rx, int ry) { +static int emu_sebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f, current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_sfpc (int rx, int ry) { - printk("sfpc emulation not implemented!\n"); +static int emu_sfpc (int rx, int ry) { + __u32 val=current->thread.regs->gprs[rx]; + if(val==0) + current->thread.fp_regs.fpc=val; + else + display_emulation_not_implemented("sfpc"); + return 0; } -static void emu_sqdb (int rx, __u64 val) { - printk("sqdb emulation not implemented!\n"); +static int emu_sqdb (int rx, __u64 val) { + display_emulation_not_implemented("sqdb"); + return 0; } -static void emu_sqdbr (int rx, int ry) { - printk("sqdbr emulation not implemented!\n"); +static int emu_sqdbr (int rx, int ry) { + display_emulation_not_implemented("sqdbr"); + return 0; } -static void emu_sqeb (int rx, __u32 val) { - printk("sqeb emulation not implemented!\n"); +static int emu_sqeb (int rx, __u32 val) { + display_emulation_not_implemented("sqeb"); + return 0; } -static void emu_sqebr (int rx, int ry) { - printk("sqebr emulation not implemented!\n"); +static int emu_sqebr (int rx, int ry) { + display_emulation_not_implemented("sqebr"); + return 0; } -static void emu_sqxbr (int rx, int ry) { - printk("sqxbr emulation not implemented!\n"); +static int emu_sqxbr (int rx, int ry) { + display_emulation_not_implemented("sqxbr"); + return 0; } -static void emu_sxbr (int rx, int ry) { - printk("sxbr emulation not implemented!\n"); +static int emu_sxbr (int rx, int ry) { + display_emulation_not_implemented("sxbr"); + return 0; } -static void emu_tcdb (int rx, __u64 val) { - printk("tcdb emulation not implemented!\n"); +static int emu_tcdb (int rx, __u64 val) { + display_emulation_not_implemented("tcdb"); + return 0; } -static void emu_tceb (int rx, __u32 val) { - printk("tceb emulation not implemented!\n"); +static int emu_tceb (int rx, __u32 val) { + display_emulation_not_implemented("tceb"); + return 0; } -static void emu_tcxb (int rx, __u64 val) { - printk("tcxb emulation not implemented!\n"); +static int emu_tcxb (int rx, __u64 val) { + display_emulation_not_implemented("tcxb"); + return 0; } @@ -473,6 +616,7 @@ } int math_emu_b3(__u8 *opcode, struct pt_regs * regs) { + int rc=0; static const __u8 format_table[] = { 2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3, @@ -538,84 +682,82 @@ emu_store_regd((opcode[3]>>4)&15); emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - emu_load_regd(opcode[3]&15); - return 0; + emu_load_regd((opcode[3]>>4)&15); + emu_load_regd(opcode[3]&15); + return rc; case 2: /* RRE format, float operation */ emu_store_rege((opcode[3]>>4)&15); emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - emu_load_rege(opcode[3]&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + emu_load_rege(opcode[3]&15); + return rc; case 3: /* RRF format, double operation */ emu_store_regd((opcode[3]>>4)&15); emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - emu_load_regd((opcode[3]>>4)&15); - emu_load_regd(opcode[3]&15); - return 0; + emu_load_regd((opcode[3]>>4)&15); + emu_load_regd(opcode[3]&15); + return rc; case 4: /* RRF format, float operation */ emu_store_rege((opcode[3]>>4)&15); emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - emu_load_rege((opcode[3]>>4)&15); - emu_load_rege(opcode[3]&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + emu_load_rege(opcode[3]&15); + return rc; case 5: /* RRE format, cefbr instruction */ emu_store_rege((opcode[3]>>4)&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + return rc; case 6: /* RRE format, cdfbr & cxfbr instruction */ emu_store_regd((opcode[3]>>4)&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - return 0; - /* FIXME !! */ - return 0; - case 7: /* RRF format, cfebr instruction */ + emu_load_regd((opcode[3]>>4)&15); + return rc; + case 7: /* RRF format, cfebr instruction */ emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - return 0; + return rc; case 8: /* RRF format, cfdbr & cfxbr instruction */ emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - return 0; + return rc; case 9: /* RRE format, ldebr & mdebr instruction */ /* float store but double load */ emu_store_rege((opcode[3]>>4)&15); emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - return 0; + emu_load_regd((opcode[3]>>4)&15); + return rc; case 10: /* RRE format, ledbr instruction */ /* double store but float load */ emu_store_regd((opcode[3]>>4)&15); emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + return rc; default: return 1; } @@ -632,6 +774,8 @@ } int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { + int rc=0; + static const __u8 format_table[] = { 0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4, 2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3, @@ -669,13 +813,12 @@ emu_store_regd((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_from_user fails ? */ - copy_from_user(&temp, dxb, 8); + mathemu_copy_from_user(&temp, dxb, 8); /* call the emulation function */ - ((void (*)(int, __u64))jump_table[opcode[5]]) + rc=((int (*)(int, __u64))jump_table[opcode[5]]) (opcode[1]>>4,temp); - emu_load_regd((opcode[1]>>4)&15); - return 0; + emu_load_regd((opcode[1]>>4)&15); + return rc; } case 2: /* RXE format, __u32 constant */ { __u32 *dxb, temp; @@ -684,13 +827,12 @@ emu_store_rege((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ - get_user(temp, dxb); + mathemu_get_user(temp, dxb); /* call the emulation function */ - ((void (*)(int, __u32))jump_table[opcode[5]]) + rc=((int (*)(int, __u32))jump_table[opcode[5]]) (opcode[1]>>4,temp); - emu_load_rege((opcode[1]>>4)&15); - return 0; + emu_load_rege((opcode[1]>>4)&15); + return rc; } case 3: /* RXF format, __u64 constant */ { __u32 *dxb, temp; @@ -699,13 +841,12 @@ emu_store_regd((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_from_user fails ? */ - copy_from_user(&temp, dxb, 8); + mathemu_copy_from_user(&temp, dxb, 8); /* call the emulation function */ - ((void (*)(int, __u32, int))jump_table[opcode[5]]) + rc=((int (*)(int, __u32, int))jump_table[opcode[5]]) (opcode[1]>>4,temp,opcode[4]>>4); - emu_load_regd((opcode[1]>>4)&15); - return 0; + emu_load_regd((opcode[1]>>4)&15); + return rc; } case 4: /* RXF format, __u32 constant */ { __u32 *dxb, temp; @@ -714,29 +855,27 @@ emu_store_rege((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ - get_user(temp, dxb); + mathemu_get_user(temp, dxb); /* call the emulation function */ - ((void (*)(int, __u32, int))jump_table[opcode[5]]) + rc=((int (*)(int, __u32, int))jump_table[opcode[5]]) (opcode[1]>>4,temp,opcode[4]>>4); emu_load_rege((opcode[1]>>4)&15); - return 0; + return rc; } case 5: /* RXE format, __u32 constant */ /* store_rege and load_regd */ - { + { __u32 *dxb, temp; __u32 opc; emu_store_rege((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ - get_user(temp, dxb); + mathemu_get_user(temp, dxb); /* call the emulation function */ - ((void (*)(int, __u32))jump_table[opcode[5]]) + rc=((int (*)(int, __u32))jump_table[opcode[5]]) (opcode[1]>>4,temp); emu_load_regd((opcode[1]>>4)&15); - return 0; + return rc; } default: return 1; @@ -746,7 +885,7 @@ /* * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6} */ -void math_emu_ldr(__u8 *opcode) { +int math_emu_ldr(__u8 *opcode) { __u16 opc = *((__u16 *) opcode); if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */ @@ -772,12 +911,13 @@ current->thread.fp_regs.fprs[(opc&0x00f0)>>4] = current->thread.fp_regs.fprs[opc&0x000f]; } + return 0; } /* * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6} */ -void math_emu_ler(__u8 *opcode) { +int math_emu_ler(__u8 *opcode) { __u16 opc = *((__u16 *) opcode); if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */ @@ -803,61 +943,68 @@ current->thread.fp_regs.fprs[(opc&0x00f0)>>4] = current->thread.fp_regs.fprs[opc&0x000f]; } + return 0; } /* * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_ld(__u8 *opcode, struct pt_regs * regs) { +int math_emu_ld(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u64 *dxb; dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_from_user fails ? */ - copy_from_user(¤t->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8); + mathemu_copy_from_user(¤t->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8); + return 0; } /* * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_le(__u8 *opcode, struct pt_regs * regs) { +int math_emu_le(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u32 *mem, *dxb; dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ mem = (__u32 *) (¤t->thread.fp_regs.fprs[(opc>>20)&15].f); - get_user(mem[0], dxb); + mathemu_get_user(mem[0], dxb); + return 0; } /* * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_std(__u8 *opcode, struct pt_regs * regs) { +int math_emu_std(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u64 *dxb; dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_to_user fails ? */ - copy_to_user(dxb, ¤t->thread.fp_regs.fprs[(opc>>20)&15].d, 8); + mathemu_copy_to_user(dxb, ¤t->thread.fp_regs.fprs[(opc>>20)&15].d, 8); + return 0; } /* * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_ste(__u8 *opcode, struct pt_regs * regs) { +int math_emu_ste(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u32 *mem, *dxb; dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if put_user fails ? */ + /* FIXME: how to react if mathemu_put_user fails ? */ mem = (__u32 *) (¤t->thread.fp_regs.fprs[(opc>>20)&15].f); - put_user(mem[0], dxb); + mathemu_put_user(mem[0], dxb); + return 0; } /* * Emulate LFPC D(B) */ int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) { - /* FIXME: how to do that ?!? */ + __u32 *dxb,temp; + __u32 opc = *((__u32 *) opcode); + dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc); + mathemu_get_user(temp, dxb); + if(temp!=0) + display_emulation_not_implemented("lfpc"); return 0; } @@ -865,7 +1012,10 @@ * Emulate STFPC D(B) */ int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) { - /* FIXME: how to do that ?!? */ + __u32 *dxb; + __u32 opc = *((__u32 *) opcode); + dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc); + mathemu_put_user(current->thread.fp_regs.fpc, dxb); return 0; } @@ -874,6 +1024,7 @@ */ int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) { /* FIXME: how to do that ?!? */ + display_emulation_not_implemented("srnm"); return 0; } diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c --- v2.4.1/linux/arch/s390/kernel/process.c Tue Sep 5 13:50:01 2000 +++ linux/arch/s390/kernel/process.c Tue Feb 13 14:13:43 2001 @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -67,7 +67,9 @@ if (softirq_active(smp_processor_id()) & softirq_mask(smp_processor_id())) { do_softirq(); - continue; + __sti(); + if (!current->need_resched) + continue; } if (current->need_resched) { schedule(); @@ -92,12 +94,13 @@ 0 returned you know you've got all the lines */ -int sprintf_regs(int line, char *buff, struct task_struct * task, - struct thread_struct *thread, struct pt_regs * regs) -{ +static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs) +{ int linelen=0; int regno,chaincnt; u32 backchain,prev_backchain,endchain; + u32 ksp = 0; + char *mode = "???"; enum { @@ -118,106 +121,125 @@ sp_kern_backchain1 }; - if(task) - thread = &task->thread; - if(thread) - regs = thread->regs; - switch (line) { - case sp_linefeed: + if (task) + ksp = task->thread.ksp; + if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE)) + ksp = regs->gprs[15]; + + if (regs) + mode = (regs->psw.mask & PSW_PROBLEM_STATE)? + "User" : "Kernel"; + + switch(line) + { + case sp_linefeed: linelen=sprintf(buff,"\n"); break; case sp_psw: if(regs) - linelen = sprintf(buff,"User PSW: %08lx %08lx\n", - (unsigned long) regs->psw.mask, - (unsigned long) regs->psw.addr); + linelen=sprintf(buff, "%s PSW: %08lx %08lx\n", mode, + (unsigned long) regs->psw.mask, + (unsigned long) regs->psw.addr); else - linelen = sprintf(buff,"pt_regs=NULL some info unavailable\n"); + linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n"); break; case sp_ksp: - if (task) - linelen += sprintf(&buff[linelen], - "task: %08x ", (addr_t)task); - if (thread) - linelen += sprintf(&buff[linelen], - "thread: %08x ksp: %08x ", - (addr_t)thread,(addr_t)thread->ksp); - if (regs) - linelen += sprintf(&buff[linelen], - "pt_regs: %08x\n", (addr_t)regs); + linelen=sprintf(&buff[linelen], + "task: %08x ksp: %08x pt_regs: %08x\n", + (addr_t)task, (addr_t)ksp, (addr_t)regs); break; case sp_gprs: - if (regs) - linelen = sprintf(buff,"User GPRS:\n"); + if(regs) + linelen=sprintf(buff, "%s GPRS:\n", mode); break; case sp_gprs1 ... sp_gprs4: - if (regs) { - regno = (line-sp_gprs1)*4; - linelen = sprintf(buff,"%08x %08x %08x %08x\n", - regs->gprs[regno], - regs->gprs[regno+1], - regs->gprs[regno+2], - regs->gprs[regno+3]); + if(regs) + { + regno=(line-sp_gprs1)*4; + linelen=sprintf(buff,"%08x %08x %08x %08x\n", + regs->gprs[regno], + regs->gprs[regno+1], + regs->gprs[regno+2], + regs->gprs[regno+3]); } break; case sp_acrs: - if (regs) - linelen = sprintf(buff,"User ACRS:\n"); + if(regs) + linelen=sprintf(buff, "%s ACRS:\n", mode); break; case sp_acrs1 ... sp_acrs4: - if (regs) { - regno = (line-sp_acrs1)*4; - linelen = sprintf(buff,"%08x %08x %08x %08x\n", - regs->acrs[regno], - regs->acrs[regno+1], - regs->acrs[regno+2], - regs->acrs[regno+3]); + if(regs) + { + regno=(line-sp_acrs1)*4; + linelen=sprintf(buff,"%08x %08x %08x %08x\n", + regs->acrs[regno], + regs->acrs[regno+1], + regs->acrs[regno+2], + regs->acrs[regno+3]); } break; case sp_kern_backchain: - if (thread && thread->ksp && regs) - linelen = sprintf(buff,"Kernel BackChain CallChain BackChain CallChain\n"); + if (regs && (regs->psw.mask & PSW_PROBLEM_STATE)) + break; + if (ksp) + linelen=sprintf(buff, "Kernel BackChain CallChain\n"); break; default: - if(thread && thread->ksp && regs) { - backchain = (thread->ksp & PSW_ADDR_MASK); - endchain = ((backchain & (-8192)) + 8192); - prev_backchain = backchain - 1; - line -= sp_kern_backchain1; - for (chaincnt = 0; ; chaincnt++) { - if ((backchain == 0) || - (backchain >= endchain) || - (chaincnt >= 8) || - (prev_backchain >= backchain)) + if (ksp) + { + + backchain=ksp&PSW_ADDR_MASK; + endchain=((backchain&(-8192))+8192); + prev_backchain=backchain-1; + line-=sp_kern_backchain1; + for(chaincnt=0;;chaincnt++) + { + if((backchain==0)||(backchain>=endchain) + ||(chaincnt>=8)||(prev_backchain>=backchain)) break; - if ((chaincnt >> 1) == line) { - linelen += sprintf(&buff[linelen],"%s%08x %08x ", - (chaincnt&1) ? "":" ", - backchain,*(u32 *)(backchain+56)); - } - if ((chaincnt >> 1) > line) + if(chaincnt==line) + { + linelen+=sprintf(&buff[linelen]," %08x [<%08lx>]\n", + backchain, + *(u32 *)(backchain+56)&PSW_ADDR_MASK); break; - prev_backchain = backchain; - backchain = (*((u32 *)backchain)) & PSW_ADDR_MASK; + } + prev_backchain=backchain; + backchain=(*((u32 *)backchain))&PSW_ADDR_MASK; } - if (linelen) - linelen += sprintf(&buff[linelen],"\n"); } } - return linelen; + return(linelen); } -void show_regs(struct task_struct *task, struct thread_struct *thread, - struct pt_regs *regs) +void show_regs(struct pt_regs *regs) { char buff[80]; int line; + + printk("CPU: %d\n",smp_processor_id()); + printk("Process %s (pid: %d, stackpage=%08X)\n", + current->comm, current->pid, 4096+(addr_t)current); - for (line = 0; sprintf_regs(line,buff,task,thread,regs); line++) + for (line = 0; sprintf_regs(line, buff, current, regs); line++) printk(buff); } +char *task_show_regs(struct task_struct *task, char *buffer) +{ + int line, len; + + for (line = 0; ; line++) + { + len = sprintf_regs(line, buffer, task, task->thread.regs); + if (!len) break; + buffer += len; + } + return buffer; +} + + int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { int clone_arg = flags | CLONE_VM; @@ -327,7 +349,7 @@ lock_kernel(); clone_flags = regs.gprs[3]; - newsp = regs.gprs[2]; + newsp = regs.orig_gpr2; if (!newsp) newsp = regs.gprs[15]; ret = do_fork(clone_flags, newsp, ®s, 0); @@ -365,7 +387,19 @@ goto out; error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], ®s); if (error == 0) - current->flags &= ~PF_DTRACE; + { + current->ptrace &= ~PT_DTRACE; + current->thread.fp_regs.fpc=0; + if(MACHINE_HAS_IEEE) + { + __asm__ __volatile__ + ("sr 0,0\n\t" + "sfpc 0,0\n\t" + : + : + :"0"); + } + } putname(filename); out: return error; @@ -412,21 +446,77 @@ unsigned long get_wchan(struct task_struct *p) { - unsigned long r14, r15; + unsigned long r14, r15, bc; unsigned long stack_page; int count = 0; if (!p || p == current || p->state == TASK_RUNNING) return 0; stack_page = (unsigned long) p; r15 = p->thread.ksp; + if (!stack_page || r15 < stack_page || r15 >= 8188+stack_page) + return 0; + bc = (*(unsigned long *) r15) & 0x7fffffff; do { - r14 = *(unsigned long *) (r15+56); + if (bc < stack_page || bc >= 8188+stack_page) + return 0; + r14 = (*(unsigned long *) (bc+56)) & 0x7fffffff; if (r14 < first_sched || r14 >= last_sched) return r14; - r15 = *(unsigned long *) (r15+60); + bc = (*(unsigned long *) bc) & 0x7fffffff; } while (count++ < 16); return 0; } #undef last_sched #undef first_sched +/* + * This should be safe even if called from tq_scheduler + * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0. + * + */ +void s390_daemonize(char *name,unsigned long mask,int use_init_fs) +{ + struct fs_struct *fs; + extern struct task_struct *child_reaper; + struct task_struct *this_process=current; + + /* + * If we were started as result of loading a module, close all of the + * user space pages. We don't need them, and if we didn't close them + * they would be locked into memory. + */ + exit_mm(current); + + this_process->session = 1; + this_process->pgrp = 1; + if(name) + { + strncpy(current->comm,name,15); + current->comm[15]=0; + } + else + current->comm[0]=0; + /* set signal mask to what we want to respond */ + siginitsetinv(¤t->blocked,mask); + /* exit_signal isn't set up */ + /* if we inherit from cpu idle */ + this_process->exit_signal=SIGCHLD; + /* if priority=0 schedule can go into a tight loop */ + this_process->policy= SCHED_OTHER; + /* nice goes priority=20-nice; */ + this_process->nice=10; + if(use_init_fs) + { + exit_fs(this_process); /* current->fs->count--; */ + fs = init_task.fs; + current->fs = fs; + atomic_inc(&fs->count); + exit_files(current); + } + write_lock_irq(&tasklist_lock); + /* We want init as our parent */ + REMOVE_LINKS(this_process); + this_process->p_opptr=this_process->p_pptr=child_reaper; + SET_LINKS(this_process); + write_unlock_irq(&tasklist_lock); +} diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/ptrace.c linux/arch/s390/kernel/ptrace.c --- v2.4.1/linux/arch/s390/kernel/ptrace.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/kernel/ptrace.c Tue Feb 13 14:13:43 2001 @@ -66,10 +66,16 @@ regs->psw.mask |=PSW_PER_MASK; else regs->psw.mask &= ~PSW_PER_MASK; - if(per_info->control_regs.bits.storage_alt_space_ctl) - task->thread.user_seg|=USER_STD_MASK; + if (per_info->control_regs.bits.em_storage_alteration) + { + per_info->control_regs.bits.storage_alt_space_ctl=1; + //((pgd_t *)__pa(task->mm->pgd))->pgd |= USER_STD_MASK; + } else - task->thread.user_seg&=~USER_STD_MASK; + { + per_info->control_regs.bits.storage_alt_space_ctl=0; + //((pgd_t *)__pa(task->mm->pgd))->pgd &= ~USER_STD_MASK; + } } void set_single_step(struct task_struct *task) @@ -209,10 +215,10 @@ if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) goto out; /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + current->ptrace |= PT_PTRACED; ret = 0; goto out; } @@ -237,9 +243,9 @@ (current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) + if (child->ptrace & PT_PTRACED) goto out; - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; write_lock_irqsave(&tasklist_lock, flags); if (child->p_pptr != current) @@ -256,16 +262,20 @@ } ret = -ESRCH; // printk("child=%lX child->flags=%lX",child,child->flags); - if (!(child->flags & PF_PTRACED)) - goto out; - if (child->state != TASK_STOPPED) + /* I added child!=current line so we can get the */ + /* ieee_instruction_pointer from the user structure DJB */ + if(child!=current) { - if (request != PTRACE_KILL) + if (!(child->ptrace & PT_PTRACED)) + goto out; + if (child->state != TASK_STOPPED) + { + if (request != PTRACE_KILL) + goto out; + } + if (child->p_pptr != current) goto out; } - if (child->p_pptr != current) - goto out; - switch (request) { /* If I and D space are separate, these will need to be fixed. */ @@ -303,9 +313,9 @@ if ((unsigned long) data >= _NSIG) break; if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; /* make sure the single step bit is not set. */ clear_single_step(child); @@ -332,7 +342,7 @@ ret = -EIO; if ((unsigned long) data >= _NSIG) break; - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; set_single_step(child); /* give it a chance to run. */ @@ -344,7 +354,7 @@ ret = -EIO; if ((unsigned long) data >= _NSIG) break; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); child->exit_code = data; write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); @@ -374,11 +384,11 @@ asmlinkage void syscall_trace(void) { lock_kernel(); - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) goto out; current->exit_code = SIGTRAP; - current->state = TASK_STOPPED; + set_current_state(TASK_STOPPED); notify_parent(current, SIGCHLD); schedule(); /* diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/reipl.S linux/arch/s390/kernel/reipl.S --- v2.4.1/linux/arch/s390/kernel/reipl.S Fri May 12 11:41:45 2000 +++ linux/arch/s390/kernel/reipl.S Tue Feb 13 14:13:43 2001 @@ -1,4 +1,13 @@ +/* + * arch/s390/kernel/reipl.S + * + * S390 version + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com) + */ + #include + .globl do_reipl do_reipl: basr %r13,0 .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) @@ -7,7 +16,7 @@ ni .Lctlsave-.Lpg0(%r13),0xef lctl %c0,%c0,.Lctlsave-.Lpg0(%r13) lr %r1,%r2 - mvc __LC_PGM_NEW_PSW(8,0),.Lpcnew-.Lpg0(%r13) + mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13) stsch .Lschib-.Lpg0(%r13) oi .Lschib+5-.Lpg0(%r13),0x84 .Lecs: xi .Lschib+27-.Lpg0(%r13),0x01 @@ -15,9 +24,9 @@ ssch .Liplorb-.Lpg0(%r13) jz .L001 bas %r14,.Ldisab-.Lpg0(%r13) -.L001: mvc __LC_IO_NEW_PSW(8,0),.Lionew-.Lpg0(%r13) +.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13) .Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13) -.Lcont: c %r1,__LC_SUBCHANNEL_ID(%r0) +.Lcont: c %r1,__LC_SUBCHANNEL_ID jnz .Ltpi clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13) jnz .Ltpi @@ -29,7 +38,7 @@ jz .L003 bas %r14,.Ldisab-.Lpg0(%r13) .L003: spx .Lnull-.Lpg0(%r13) - st %r1,__LC_SUBCHANNEL_ID(%r0) + st %r1,__LC_SUBCHANNEL_ID lpsw 0 sigp 0,0,0(6) .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/s390_ext.c linux/arch/s390/kernel/s390_ext.c --- v2.4.1/linux/arch/s390/kernel/s390_ext.c Wed Dec 31 16:00:00 1969 +++ linux/arch/s390/kernel/s390_ext.c Tue Feb 13 14:13:43 2001 @@ -0,0 +1,77 @@ +/* + * arch/s390/kernel/s390_ext.c + * + * S390 version + * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com), + * Martin Schwidefsky (schwidefsky@de.ibm.com) + */ + +#include +#include +#include +#include + +/* + * Simple hash strategy: index = code & 0xff; + * ext_int_hash[index] is the start of the list for all external interrupts + * that hash to this index. With the current set of external interrupts + * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000 + * iucv) this is always the first element. + */ +ext_int_info_t *ext_int_hash[256] = { 0, }; +ext_int_info_t ext_int_info_timer; +ext_int_info_t ext_int_info_hwc; + +int register_external_interrupt(__u16 code, ext_int_handler_t handler) { + ext_int_info_t *p; + int index; + + index = code & 0xff; + p = ext_int_hash[index]; + while (p != NULL) { + if (p->code == code) + return -EBUSY; + p = p->next; + } + if (code == 0x1004) /* time_init is done before kmalloc works :-/ */ + p = &ext_int_info_timer; + else if (code == 0x2401) /* hwc_init is done too early too */ + p = &ext_int_info_hwc; + else + p = (ext_int_info_t *) + kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC); + if (p == NULL) + return -ENOMEM; + p->code = code; + p->handler = handler; + p->next = ext_int_hash[index]; + ext_int_hash[index] = p; + return 0; +} + +int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) { + ext_int_info_t *p, *q; + int index; + + index = code & 0xff; + q = NULL; + p = ext_int_hash[index]; + while (p != NULL) { + if (p->code == code && p->handler == handler) + break; + q = p; + p = p->next; + } + if (p == NULL) + return -ENOENT; + if (q != NULL) + q->next = p->next; + else + ext_int_hash[index] = p->next; + if (code != 0x1004 && code != 0x2401) + kfree(p); + return 0; +} + + diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c --- v2.4.1/linux/arch/s390/kernel/s390_ksyms.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/kernel/s390_ksyms.c Tue Feb 13 14:13:43 2001 @@ -5,14 +5,27 @@ */ #include #include +#include +#include +#include #include -#include +#include +#include +#include #include +#include +#if CONFIG_CHANDEV +#include +#endif +#if CONFIG_IP_MULTICAST +#include +#endif /* * I/O subsystem */ EXPORT_SYMBOL(halt_IO); +EXPORT_SYMBOL(clear_IO); EXPORT_SYMBOL(do_IO); EXPORT_SYMBOL(resume_IO); EXPORT_SYMBOL(ioinfo); @@ -22,6 +35,35 @@ EXPORT_SYMBOL(get_devno_by_irq); EXPORT_SYMBOL(get_irq_first); EXPORT_SYMBOL(get_irq_next); +EXPORT_SYMBOL(read_conf_data); +EXPORT_SYMBOL(read_dev_chars); +EXPORT_SYMBOL(s390_request_irq_special); +EXPORT_SYMBOL(s390_device_register); +EXPORT_SYMBOL(s390_device_unregister); + +EXPORT_SYMBOL(ccw_alloc_request); +EXPORT_SYMBOL(ccw_free_request); + +EXPORT_SYMBOL(register_external_interrupt); +EXPORT_SYMBOL(unregister_external_interrupt); + +/* + * debug feature + */ +EXPORT_SYMBOL(debug_register); +EXPORT_SYMBOL(debug_unregister); +EXPORT_SYMBOL(debug_set_level); +EXPORT_SYMBOL(debug_register_view); +EXPORT_SYMBOL(debug_unregister_view); +EXPORT_SYMBOL(debug_event); +EXPORT_SYMBOL(debug_int_event); +EXPORT_SYMBOL(debug_text_event); +EXPORT_SYMBOL(debug_exception); +EXPORT_SYMBOL(debug_int_exception); +EXPORT_SYMBOL(debug_text_exception); +EXPORT_SYMBOL(debug_hex_ascii_view); +EXPORT_SYMBOL(debug_raw_view); +EXPORT_SYMBOL(debug_dflt_header_fn); /* * memory management @@ -29,6 +71,16 @@ EXPORT_SYMBOL(_oi_bitmap); EXPORT_SYMBOL(_ni_bitmap); EXPORT_SYMBOL(_zb_findmap); +EXPORT_SYMBOL(__copy_from_user_fixup); +EXPORT_SYMBOL(__copy_to_user_fixup); + +/* + * semaphore ops + */ +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__down_trylock); /* * string functions @@ -36,6 +88,7 @@ EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(strlen); EXPORT_SYMBOL_NOVERS(strchr); EXPORT_SYMBOL_NOVERS(strcmp); EXPORT_SYMBOL_NOVERS(strncat); @@ -46,19 +99,42 @@ EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); +EXPORT_SYMBOL_NOVERS(_ascebc_500); +EXPORT_SYMBOL_NOVERS(_ebcasc_500); +EXPORT_SYMBOL_NOVERS(_ascebc); +EXPORT_SYMBOL_NOVERS(_ebcasc); +EXPORT_SYMBOL_NOVERS(_ebc_tolower); +EXPORT_SYMBOL_NOVERS(_ebc_toupper); + /* * misc. */ +EXPORT_SYMBOL(module_list); +EXPORT_SYMBOL(__udelay); #ifdef CONFIG_SMP #include EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(lowcore_ptr); EXPORT_SYMBOL(global_bh_lock); EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(smp_ctl_set_bit); +EXPORT_SYMBOL(smp_ctl_clear_bit); #endif EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(csum_fold); - +#if CONFIG_CHANDEV +EXPORT_SYMBOL(chandev_register_and_probe); +EXPORT_SYMBOL(chandev_request_irq); +EXPORT_SYMBOL(chandev_unregister); +EXPORT_SYMBOL(chandev_initdevice); +EXPORT_SYMBOL(chandev_initnetdevice); +#endif +#if CONFIG_IP_MULTICAST +/* Required for lcs gigabit ethernet multicast support */ +EXPORT_SYMBOL(arp_mc_map); +#endif +EXPORT_SYMBOL(s390_daemonize); diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/s390dyn.c linux/arch/s390/kernel/s390dyn.c --- v2.4.1/linux/arch/s390/kernel/s390dyn.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/kernel/s390dyn.c Wed Dec 31 16:00:00 1969 @@ -1,36 +0,0 @@ -/* - * arch/s390/kernel/s390dyn.c - * S/390 dynamic device attachment - * - * S390 version - * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Ingo Adlung (adlung@de.ibm.com) - */ - -#include - -#include -#include -#include - -int s390_device_register( devreg_t *drinfo ) -{ - return -EOPNOTSUPP; -} - - -int s390_device_deregister ( devreg_t *dreg ) -{ - return -EOPNOTSUPP; -} - -int s390_request_irq_special( int irq, - io_handler_func_t io_handler, - not_oper_handler_func_t not_oper_handler, - unsigned long irqflags, - const char *devname, - void *dev_id) -{ - return -EOPNOTSUPP; -} - diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/s390fpu.c linux/arch/s390/kernel/s390fpu.c --- v2.4.1/linux/arch/s390/kernel/s390fpu.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/kernel/s390fpu.c Tue Feb 13 14:13:43 2001 @@ -81,6 +81,11 @@ { int has_ieee=MACHINE_HAS_IEEE; + /* If we don't mask with the FPC_VALID_MASK here + * we've got a very quick shutdown -h now command + * via a kernel specification exception. + */ + fpregs->fpc&=FPC_VALID_MASK; asm volatile ("LD 0,8(%0)\n\t" "LD 2,24(%0)\n\t" "LD 4,40(%0)\n\t" diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/s390io.c linux/arch/s390/kernel/s390io.c --- v2.4.1/linux/arch/s390/kernel/s390io.c Fri Aug 4 16:15:37 2000 +++ linux/arch/s390/kernel/s390io.c Wed Dec 31 16:00:00 1969 @@ -1,4605 +0,0 @@ -/* - * arch/s390/kernel/s390io.c - * S/390 common I/O routines - * - * S390 version - * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Ingo Adlung (adlung@de.ibm.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#undef CONFIG_DEBUG_IO - -#define REIPL_DEVID_MAGIC 0x87654321 - -struct irqaction init_IRQ_action; -unsigned int highest_subchannel; -ioinfo_t *ioinfo_head = NULL; -ioinfo_t *ioinfo_tail = NULL; -ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = { - [0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA -}; - -static spinlock_t sync_isc; // synchronous irq processing lock -static psw_t io_sync_wait; // wait PSW for sync IO, prot. by sync_isc -static psw_t io_new_psw; // save I/O new PSW, prot. by sync_isc -static int cons_dev = -1; // identify console device -static int init_IRQ_complete = 0; -static schib_t init_schib; -static __u64 irq_IPL_TOD; - -/* - * Dummy controller type for unused interrupts - */ -int do_none(unsigned int irq, int cpu, struct pt_regs * regs) { return 0;} -int enable_none(unsigned int irq) { return(-ENODEV); } -int disable_none(unsigned int irq) { return(-ENODEV); } - -struct hw_interrupt_type no_irq_type = { - "none", - do_none, - enable_none, - disable_none -}; - -static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs); -static int s390_setup_irq(unsigned int irq, struct irqaction * new); -static void s390_process_subchannels( void); -static void s390_device_recognition( void); -static int s390_validate_subchannel( int irq); -static int s390_SenseID( int irq, senseid_t *sid); -static int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid); -static int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid); -static int s390_process_IRQ( unsigned int irq ); -static int s390_DevicePathVerification( int irq ); - -extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs); -extern int enable_none(unsigned int irq); -extern int disable_none(unsigned int irq); -extern void tod_wait(unsigned long usecs); - -asmlinkage void do_IRQ( struct pt_regs regs, - unsigned int irq, - __u32 s390_intparm ); - -void s390_displayhex(char *str,void *ptr,s32 cnt); - -void s390_displayhex(char *str,void *ptr,s32 cnt) -{ - s32 cnt1,cnt2,maxcnt2; - u32 *currptr=(__u32 *)ptr; - - printk("\n%s\n",str); - - for(cnt1=0;cnt116) - maxcnt2=16; - for(cnt2=0;cnt2= __MAX_SUBCHANNELS) - return -EINVAL; - - if ( !handler || !dev_id ) - return -EINVAL; - - /* - * during init_IRQ() processing we don't have memory - * management yet, thus need to use a statically - * allocated irqaction control block - */ - if ( init_IRQ_complete ) - { - action = (struct irqaction *) - kmalloc(sizeof(struct irqaction), GFP_KERNEL); - } - else - { - action = &init_IRQ_action; - - } /* endif */ - - if (!action) - { - return -ENOMEM; - - } /* endif */ - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->next = NULL; - action->dev_id = dev_id; - - retval = s390_setup_irq( irq, action); - - if ( !retval ) - { - retval = s390_DevicePathVerification( irq ); - } - else if ( retval && init_IRQ_complete ) - { - kfree(action); - - } /* endif */ - - return retval; -} - -void s390_free_irq(unsigned int irq, void *dev_id) -{ - unsigned int flags; - int ret; - - unsigned int count = 0; - - if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return; - - } /* endif */ - - s390irq_spin_lock_irqsave( irq, flags); - -#ifdef CONFIG_KERNEL_DEBUG - if ( irq != cons_dev ) - { - printk("Trying to free IRQ%d\n",irq); - - } /* endif */ -#endif - - /* - * disable the device and reset all IRQ info if - * the IRQ is actually owned by the handler ... - */ - if ( ioinfo[irq]->irq_desc.action ) - { - if ( (dev_id == ioinfo[irq]->irq_desc.action->dev_id ) - || (dev_id == (devstat_t *)REIPL_DEVID_MAGIC) ) - { - /* start deregister */ - ioinfo[irq]->ui.flags.unready = 1; - - do - { - ret = ioinfo[irq]->irq_desc.handler->disable(irq); - - count++; - - if ( ret == -EBUSY ) - { - int iret; - - /* - * kill it ! - * ... we first try sync and eventually - * try terminating the current I/O by - * an async request, twice halt, then - * clear. - */ - if ( count < 3 ) - { - iret = halt_IO( irq, - 0xC8C1D3E3, - DOIO_WAIT_FOR_INTERRUPT ); - - if ( iret == -EBUSY ) - { - halt_IO( irq, 0xC8C1D3E3, 0); - s390irq_spin_unlock_irqrestore( irq, flags); - tod_wait( 200000 ); /* 200 ms */ - s390irq_spin_lock_irqsave( irq, flags); - - } /* endif */ - } - else - { - iret = clear_IO( irq, - 0x40C3D3D9, - DOIO_WAIT_FOR_INTERRUPT ); - - if ( iret == -EBUSY ) - { - clear_IO( irq, 0xC8C1D3E3, 0); - s390irq_spin_unlock_irqrestore( irq, flags); - tod_wait( 1000000 ); /* 1000 ms */ - s390irq_spin_lock_irqsave( irq, flags); - - } /* endif */ - - } /* endif */ - - if ( count == 3 ) - { - /* give it a very last try ... */ - ioinfo[irq]->irq_desc.handler->disable(irq); - - if ( ioinfo[irq]->ui.flags.busy ) - { - printk( KERN_CRIT"free_irq(%04X) " - "- device %04X busy, retry " - "count exceeded\n", - irq, - ioinfo[irq]->devstat.devno); - - } /* endif */ - - break; /* sigh, let's give up ... */ - - } /* endif */ - - } /* endif */ - - } while ( ret == -EBUSY ); - - if ( init_IRQ_complete ) - kfree( ioinfo[irq]->irq_desc.action ); - - ioinfo[irq]->irq_desc.action = NULL; - ioinfo[irq]->ui.flags.ready = 0; - - ioinfo[irq]->irq_desc.handler->enable = &enable_none; - ioinfo[irq]->irq_desc.handler->disable = &disable_none; - - ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ - - s390irq_spin_unlock_irqrestore( irq, flags); - } - else - { - s390irq_spin_unlock_irqrestore( irq, flags); - - printk("free_irq() : error, dev_id does not match !"); - - } /* endif */ - - } - else - { - s390irq_spin_unlock_irqrestore( irq, flags); - - printk("free_irq() : error, no action block ... !"); - - } /* endif */ - -} - -/* - * Generic enable/disable code - */ -int disable_irq(unsigned int irq) -{ - unsigned long flags; - int ret; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - return( -ENODEV); - - s390irq_spin_lock_irqsave(irq, flags); - - /* - * At this point we may actually have a pending interrupt being active - * on another CPU. So don't touch the IRQ_INPROGRESS bit.. - */ - ioinfo[irq]->irq_desc.status |= IRQ_DISABLED; - ret = ioinfo[irq]->irq_desc.handler->disable(irq); - s390irq_spin_unlock_irqrestore(irq, flags); - - synchronize_irq(); - - return( ret); -} - -int enable_irq(unsigned int irq) -{ - unsigned long flags; - int ret; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - return( -ENODEV); - - s390irq_spin_lock_irqsave(irq, flags); - - ioinfo[irq]->irq_desc.status = 0; - ret = ioinfo[irq]->irq_desc.handler->enable(irq); - - s390irq_spin_unlock_irqrestore(irq, flags); - - return(ret); -} - -/* - * Enable IRQ by modifying the subchannel - */ -static int enable_subchannel( unsigned int irq) -{ - int ret; - int ccode; - int retry = 5; - - if ( irq > highest_subchannel || irq < 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - return( -ENODEV); - - /* - * If a previous disable request is pending we reset it. However, this - * status implies that the device may (still) be not-operational. - */ - if ( ioinfo[irq]->ui.flags.d_disable ) - { - ioinfo[irq]->ui.flags.d_disable = 0; - ret = 0; - } - else - { - - ccode = stsch(irq, &(ioinfo[irq]->schib) ); - - if ( ccode ) - { - ret = -ENODEV; - } - else - { - ioinfo[irq]->schib.pmcw.ena = 1; - - do - { - ccode = msch( irq, &(ioinfo[irq]->schib) ); - - switch (ccode) { - case 0: - ret = 0; - break; - - case 1: - /* - * very bad, requires interrupt alike - * processing, where "rbh" is a dummy - * parameter for interface compatibility - * only. Bottom-half handling cannot be - * required as this must be an - * unsolicited interrupt (!busy). - */ - - ioinfo[irq]->ui.flags.s_pend = 1; - - s390_process_IRQ( irq ); - - ioinfo[irq]->ui.flags.s_pend = 0; - - ret = -EIO; /* might be overwritten */ - /* ... on re-driving */ - /* ... the msch() */ - retry--; - break; - - case 3: - ioinfo[irq]->ui.flags.oper = 0; - ret = -ENODEV; - break; - - default: - printk( KERN_CRIT"enable_subchannel(%04X) " - " : ccode 2 on msch() for device " - "%04X received !\n", - irq, - ioinfo[irq]->devstat.devno); - ret = -ENODEV; // never reached - } - - } while ( (ccode == 1) && retry ); - - } /* endif */ - - } /* endif */ - - return( ret ); -} - - -/* - * Disable IRQ by modifying the subchannel - */ -static int disable_subchannel( unsigned int irq) -{ - int cc; /* condition code */ - int ret; /* function return value */ - int retry = 5; - - if ( irq > highest_subchannel ) - { - ret = -ENODEV; - } - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - else if ( ioinfo[irq]->ui.flags.busy ) - { - /* - * the disable function must not be called while there are - * requests pending for completion ! - */ - ret = -EBUSY; - } - else - { - /* - * If device isn't operational we have to perform delayed - * disabling when the next interrupt occurs - unless the - * irq is re-requested prior to the interrupt to occur. - */ - cc = stsch(irq, &(ioinfo[irq]->schib) ); - - if ( cc == 3 ) - { - ioinfo[irq]->ui.flags.oper = 0; - ioinfo[irq]->ui.flags.d_disable = 1; - - ret = 0; - } - else // cc == 0 - { - ioinfo[irq]->schib.pmcw.ena = 0; - - do - { - cc = msch( irq, &(ioinfo[irq]->schib) ); - - switch (cc) { - case 0 : - ret = 0; /* done */ - break; - - case 1 : - /* - * very bad, requires interrupt alike - * processing, where "rbh" is a dummy - * parm for interface compatibility - * only. Bottom-half handling cannot - * be required as this must be an - * unsolicited interrupt (!busy). - */ - ioinfo[irq]->ui.flags.s_pend = 1; - s390_process_IRQ( irq ); - ioinfo[irq]->ui.flags.s_pend = 0; - - ret = -EBUSY; /* might be overwritten */ - /* ... on re-driving the */ - /* ... msch() call */ - retry--; - break; - - case 2 : - /* - * *** must not occur ! *** - * *** *** - * *** indicates our internal *** - * *** interrupt accounting is out *** - * *** of sync ===> panic() *** - */ - printk( KERN_CRIT"disable_subchannel(%04X) " - "- unexpected busy condition for " - "device %04X received !\n", - irq, - ioinfo[irq]->devstat.devno); - - ret = -ENODEV; // never reached - break; - - case 3 : - /* - * should hardly occur ?! - */ - ioinfo[irq]->ui.flags.oper = 0; - ioinfo[irq]->ui.flags.d_disable = 1; - - ret = 0; /* if the device has gone we */ - /* ... don't need to disable */ - /* ... it anymore ! */ - break; - - default : - ret = -ENODEV; // never reached ... - break; - - } /* endswitch */ - - } while ( (cc == 1) && retry ); - - } /* endif */ - - } /* endif */ - - return( ret); -} - - - -int s390_setup_irq( unsigned int irq, struct irqaction * new) -{ - unsigned long flags; - int rc = 0; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* - * The following block of code has to be executed atomically - */ - s390irq_spin_lock_irqsave( irq, flags); - - if ( ioinfo[irq]->irq_desc.action == NULL ) - { - ioinfo[irq]->irq_desc.action = new; - ioinfo[irq]->irq_desc.status = 0; - ioinfo[irq]->irq_desc.handler->enable = &enable_subchannel; - ioinfo[irq]->irq_desc.handler->disable = &disable_subchannel; - ioinfo[irq]->irq_desc.handler->handle = &handle_IRQ_event; - - ioinfo[irq]->ui.flags.ready = 1; - - ioinfo[irq]->irq_desc.handler->enable(irq); - } - else - { - /* - * interrupt already owned, and shared interrupts - * aren't supported on S/390. - */ - rc = -EBUSY; - - } /* endif */ - - s390irq_spin_unlock_irqrestore(irq,flags); - - return( rc); -} - -void s390_init_IRQ( void ) -{ - unsigned long flags; /* PSW flags */ - long cr6 __attribute__ ((aligned (8))); - - // Hopefully bh_count's will get set when we copy the prefix lowcore - // structure to other CPI's ( DJB ) - softirq_active(smp_processor_id()) = 0; - softirq_mask(smp_processor_id()) = 0; - local_bh_count(smp_processor_id()) = 0; - local_irq_count(smp_processor_id()) = 0; - syscall_count(smp_processor_id()) = 0; - - asm volatile ("STCK %0" : "=m" (irq_IPL_TOD)); - - /* - * As we don't know about the calling environment - * we assure running disabled. Before leaving the - * function we resestablish the old environment. - * - * Note : as we don't need a system wide lock, therefore - * we shouldn't use cli(), but __cli() as this - * affects the current CPU only. - */ - __save_flags(flags); - __cli(); - - /* - * disable all interrupts - */ - cr6 = 0; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - s390_process_subchannels(); - - /* - * enable default I/O-interrupt sublass 3 - */ - cr6 = 0x10000000; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - s390_device_recognition(); - - init_IRQ_complete = 1; - - s390_init_machine_check(); - - __restore_flags(flags); - - return; -} - - -/* - * dummy handler, used during init_IRQ() processing for compatibility only - */ -void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs) -{ - /* this is a dummy handler only ... */ -} - - -int s390_start_IO( int irq, /* IRQ */ - ccw1_t *cpa, /* logical channel prog addr */ - unsigned long user_intparm, /* interruption parameter */ - __u8 lpm, /* logical path mask */ - unsigned long flag) /* flags */ -{ - int ccode; - unsigned long psw_flags; - - int sync_isc_locked = 0; - int ret = 0; - - /* - * The flag usage is mutal exclusive ... - */ - if ( (flag & DOIO_RETURN_CHAN_END) - && (flag & DOIO_REPORT_ALL ) ) - { - return( -EINVAL ); - - } /* endif */ - - memset( &(ioinfo[irq]->orb), '\0', sizeof( orb_t) ); - - /* - * setup ORB - */ - ioinfo[irq]->orb.intparm = (__u32)&ioinfo[irq]->u_intparm; - ioinfo[irq]->orb.fmt = 1; - - ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH); - ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND); - ioinfo[irq]->orb.ssic = ( (flag & DOIO_ALLOW_SUSPEND ) - && (flag & DOIO_SUPPRESS_INTER) ); - - if ( flag & DOIO_VALID_LPM ) - { - ioinfo[irq]->orb.lpm = lpm; - } - else - { - ioinfo[irq]->orb.lpm = ioinfo[irq]->opm; - - } /* endif */ - - ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa); - - /* - * If sync processing was requested we lock the sync ISC, modify the - * device to present interrupts for this ISC only and switch the - * CPU to handle this ISC + the console ISC exclusively. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - // - // check whether we run recursively (sense processing) - // - if ( !ioinfo[irq]->ui.flags.syncio ) - { - spin_lock_irqsave( &sync_isc, psw_flags); - - ret = enable_cpu_sync_isc( irq); - - if ( ret ) - { - spin_unlock_irqrestore( &sync_isc, psw_flags); - return( ret); - } - else - { - sync_isc_locked = 1; // local - ioinfo[irq]->ui.flags.syncio = 1; // global - - } /* endif */ - - } /* endif */ - - } /* endif */ - - /* - * Issue "Start subchannel" and process condition code - */ - ccode = ssch( irq, &(ioinfo[irq]->orb) ); - - switch ( ccode ) { - case 0: - - if ( !ioinfo[irq]->ui.flags.w4sense ) - { - /* - * init the device driver specific devstat irb area - * - * Note : dont clear saved irb info in case of sense ! - */ - memset( &((devstat_t *)ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, - '\0', sizeof( irb_t) ); - } /* endif */ - - /* - * initialize device status information - */ - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->ui.flags.doio = 1; - - ioinfo[irq]->u_intparm = user_intparm; - ioinfo[irq]->devstat.cstat = 0; - ioinfo[irq]->devstat.dstat = 0; - ioinfo[irq]->devstat.lpum = 0; - ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION; - ioinfo[irq]->devstat.scnt = 0; - - ioinfo[irq]->ui.flags.fast = 0; - ioinfo[irq]->ui.flags.repall = 0; - - /* - * Check for either early (FAST) notification requests - * or if we are to return all interrupt info. - * Default is to call IRQ handler at secondary status only - */ - if ( flag & DOIO_RETURN_CHAN_END ) - { - ioinfo[irq]->ui.flags.fast = 1; - } - else if ( flag & DOIO_REPORT_ALL ) - { - ioinfo[irq]->ui.flags.repall = 1; - - } /* endif */ - - ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm; - - /* - * If synchronous I/O processing is requested, we have - * to wait for the corresponding interrupt to occur by - * polling the interrupt condition. However, as multiple - * interrupts may be outstanding, we must not just wait - * for the first interrupt, but must poll until ours - * pops up. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - // __u32 io_parm; - psw_t io_new_psw; - int ccode; - - int ready = 0; - int io_sub = -1; - struct _lowcore *lc = NULL; - int count = 30000; - - /* - * We shouldn't perform a TPI loop, waiting for an - * interrupt to occur, but should load a WAIT PSW - * instead. Otherwise we may keep the channel subsystem - * busy, not able to present the interrupt. When our - * sync. interrupt arrived we reset the I/O old PSW to - * its original value. - */ - memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t)); - - ccode = iac(); - - switch (ccode) { - case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; - break; - case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; - break; - default: - panic( "start_IO() : unexpected " - "address-space-control %d\n", - ccode); - break; - } /* endswitch */ - - io_sync_wait.addr = FIX_PSW(&&io_wakeup); - - /* - * Martin didn't like modifying the new PSW, now we take - * a fast exit in do_IRQ() instead - */ - *(__u32 *)__LC_SYNC_IO_WORD = 1; - - do - { - if ( flag & DOIO_TIMEOUT ) - { - tpi_info_t tpi_info; - - do - { - if ( tpi(&tpi_info) == 1 ) - { - io_sub = tpi_info.irq; - break; - } - else - { - count--; - tod_wait(100); /* usecs */ - - } /* endif */ - - } while ( count ); - } - else - { - asm volatile ("lpsw %0" : : "m" (io_sync_wait)); - -io_wakeup: - io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; - - } /* endif */ - - if ( count ) - ready = s390_process_IRQ( io_sub ); - - /* - * surrender when retry count's exceeded ... - */ - - } while ( !( ( io_sub == irq ) - && ( ready == 1 )) - && count ); - - *(__u32 *)__LC_SYNC_IO_WORD = 0; - - if ( !count ) - ret = -ETIMEDOUT; - - } /* endif */ - - break; - - case 1 : /* status pending */ - - ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING; - - /* - * initialize the device driver specific devstat irb area - */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, - '\0', sizeof( irb_t) ); - - /* - * Let the common interrupt handler process the pending status. - * However, we must avoid calling the user action handler, as - * it won't be prepared to handle a pending status during - * do_IO() processing inline. This also implies that process_IRQ - * must terminate synchronously - especially if device sensing - * is required. - */ - ioinfo[irq]->ui.flags.s_pend = 1; - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->ui.flags.doio = 1; - - s390_process_IRQ( irq ); - - ioinfo[irq]->ui.flags.s_pend = 0; - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.doio = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - - ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; - - /* - * In multipath mode a condition code 3 implies the last path - * has gone, except we have previously restricted the I/O to - * a particular path. A condition code 1 (0 won't occur) - * results in return code EIO as well as 3 with another path - * than the one used (i.e. path available mask is non-zero). - */ - if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 ) - { - ret = -ENODEV; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 0; - -#if CONFIG_DEBUG_IO - { - char buffer[80]; - - stsch(irq, &(ioinfo[irq]->schib) ); - - sprintf( buffer, "s390_start_IO(%04X) - irb for " - "device %04X, after status pending\n", - irq, - ioinfo[irq]->devstat.devno ); - - s390_displayhex( buffer, - &(ioinfo[irq]->devstat.ii.irb) , - sizeof(irb_t)); - - sprintf( buffer, "s390_start_IO(%04X) - schib for " - "device %04X, after status pending\n", - irq, - ioinfo[irq]->devstat.devno ); - - s390_displayhex( buffer, - &(ioinfo[irq]->schib) , - sizeof(schib_t)); - - - if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) - { - sprintf( buffer, "s390_start_IO(%04X) - sense " - "data for " - "device %04X, after status pending\n", - irq, - ioinfo[irq]->devstat.devno ); - - s390_displayhex( buffer, - ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->ii.sense.data, - ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt); - - } - } -#endif - } - else - { - ret = -EIO; - ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 1; - - } /* endif */ - - break; - - case 2 : /* busy */ - - ret = -EBUSY; - break; - - default: /* device not operational */ - - ret = -ENODEV; - ioinfo[irq]->ui.flags.oper = 0; - - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - - memcpy( ioinfo[irq]->irq_desc.action->dev_id, - &(ioinfo[irq]->devstat), - sizeof( devstat_t) ); - -#if CONFIG_DEBUG_IO - { - char buffer[80]; - - stsch(irq, &(ioinfo[irq]->schib) ); - - sprintf( buffer, "s390_start_IO(%04X) - schib for " - "device %04X, after 'not oper' status\n", - irq, - ioinfo[irq]->devstat.devno ); - - s390_displayhex( buffer, - &(ioinfo[irq]->schib), - sizeof(schib_t)); - } -#endif - break; - - } /* endswitch */ - - if ( ( flag & DOIO_WAIT_FOR_INTERRUPT ) - && ( sync_isc_locked ) ) - { - disable_cpu_sync_isc( irq ); - - spin_unlock_irqrestore( &sync_isc, psw_flags); - - sync_isc_locked = 0; // local setting - ioinfo[irq]->ui.flags.syncio = 0; // global setting - - } /* endif */ - - return( ret); -} - -int do_IO( int irq, /* IRQ */ - ccw1_t *cpa, /* channel program address */ - unsigned long user_intparm, /* interruption parameter */ - __u8 lpm, /* logical path mask */ - unsigned long flag) /* flags : see above */ -{ - int ret = 0; - - if ( irq > highest_subchannel || irq < 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* handler registered ? or free_irq() in process already ? */ - if ( !ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready ) - { - return( -ENODEV ); - - } /* endif */ - - /* - * Note: We ignore the device operational status - if not operational, - * the SSCH will lead to an -ENODEV condition ... - */ - if ( !ioinfo[irq]->ui.flags.busy ) /* last I/O completed ? */ - { - ret = s390_start_IO( irq, cpa, user_intparm, lpm, flag); - } - else if ( ioinfo[irq]->ui.flags.fast ) - { - /* - * If primary status was received and ending status is missing, - * the device driver won't be notified on the ending status - * if early (fast) interrupt notification was requested. - * Therefore we have to queue the next incoming request. If - * halt_IO() is issued while there is a request queued, a HSCH - * needs to be issued and the queued request must be deleted - * but its intparm must be returned (see halt_IO() processing) - */ - if ( ioinfo[irq]->ui.flags.w4final - && !ioinfo[irq]->ui.flags.doio_q ) - { - ioinfo[irq]->qflag = flag; - ioinfo[irq]->qcpa = cpa; - ioinfo[irq]->qintparm = user_intparm; - ioinfo[irq]->qlpm = lpm; - } - else - { - ret = -EBUSY; - - } /* endif */ - } - else - { - ret = -EBUSY; - - } /* endif */ - - return( ret ); - -} - -/* - * resume suspended I/O operation - */ -int resume_IO( int irq) -{ - int ret = 0; - - if ( irq > highest_subchannel || irq < 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* - * We allow for 'resume' requests only for active I/O operations - */ - if ( ioinfo[irq]->ui.flags.busy ) - { - int ccode; - - ccode = rsch( irq); - - switch (ccode) { - case 0 : - break; - - case 1 : - s390_process_IRQ( irq ); - ret = -EBUSY; - break; - - case 2 : - ret = -EINVAL; - break; - - case 3 : - /* - * useless to wait for request completion - * as device is no longer operational ! - */ - ioinfo[irq]->ui.flags.oper = 0; - ioinfo[irq]->ui.flags.busy = 0; - ret = -ENODEV; - break; - - } /* endswitch */ - - } - else - { - ret = -ENOTCONN; - - } /* endif */ - - return( ret); -} - -/* - * Note: The "intparm" parameter is not used by the halt_IO() function - * itself, as no ORB is built for the HSCH instruction. However, - * it allows the device interrupt handler to associate the upcoming - * interrupt with the halt_IO() request. - */ -int halt_IO( int irq, - unsigned long user_intparm, - unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */ -{ - int ret; - int ccode; - unsigned long psw_flags; - - int sync_isc_locked = 0; - - if ( irq > highest_subchannel || irq < 0 ) - { - ret = -ENODEV; - } - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* - * we only allow for halt_IO if the device has an I/O handler associated - */ - else if ( !ioinfo[irq]->ui.flags.ready ) - { - ret = -ENODEV; - } - /* - * we ignore the halt_io() request if ending_status was received but - * a SENSE operation is waiting for completion. - */ - else if ( ioinfo[irq]->ui.flags.w4sense ) - { - ret = 0; - } - /* - * We don't allow for halt_io with a sync do_IO() requests pending. - */ - else if ( ioinfo[irq]->ui.flags.syncio ) - { - ret = -EBUSY; - } - else - { - /* - * If sync processing was requested we lock the sync ISC, - * modify the device to present interrupts for this ISC only - * and switch the CPU to handle this ISC + the console ISC - * exclusively. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - // - // check whether we run recursively (sense processing) - // - if ( !ioinfo[irq]->ui.flags.syncio ) - { - spin_lock_irqsave( &sync_isc, psw_flags); - - ret = enable_cpu_sync_isc( irq); - - if ( ret ) - { - spin_unlock_irqrestore( &sync_isc, - psw_flags); - return( ret); - } - else - { - sync_isc_locked = 1; // local - ioinfo[irq]->ui.flags.syncio = 1; // global - - } /* endif */ - - } /* endif */ - - } /* endif */ - - /* - * Issue "Halt subchannel" and process condition code - */ - ccode = hsch( irq ); - - switch ( ccode ) { - case 0: - - ioinfo[irq]->ui.flags.haltio = 1; - - if ( !ioinfo[irq]->ui.flags.doio ) - { - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->u_intparm = user_intparm; - ioinfo[irq]->devstat.cstat = 0; - ioinfo[irq]->devstat.dstat = 0; - ioinfo[irq]->devstat.lpum = 0; - ioinfo[irq]->devstat.flag = DEVSTAT_HALT_FUNCTION; - ioinfo[irq]->devstat.scnt = 0; - - } - else - { - ioinfo[irq]->devstat.flag |= DEVSTAT_HALT_FUNCTION; - - } /* endif */ - - /* - * If synchronous I/O processing is requested, we have - * to wait for the corresponding interrupt to occur by - * polling the interrupt condition. However, as multiple - * interrupts may be outstanding, we must not just wait - * for the first interrupt, but must poll until ours - * pops up. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - int io_sub; - __u32 io_parm; - psw_t io_new_psw; - int ccode; - - int ready = 0; - struct _lowcore *lc = NULL; - - /* - * We shouldn't perform a TPI loop, waiting for - * an interrupt to occur, but should load a - * WAIT PSW instead. Otherwise we may keep the - * channel subsystem busy, not able to present - * the interrupt. When our sync. interrupt - * arrived we reset the I/O old PSW to its - * original value. - */ - memcpy( &io_new_psw, - &lc->io_new_psw, - sizeof(psw_t)); - - ccode = iac(); - - switch (ccode) { - case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; - break; - case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; - break; - default: - panic( "halt_IO() : unexpected " - "address-space-control %d\n", - ccode); - break; - } /* endswitch */ - - io_sync_wait.addr = FIX_PSW(&&hio_wakeup); - - /* - * Martin didn't like modifying the new PSW, now we take - * a fast exit in do_IRQ() instead - */ - *(__u32 *)__LC_SYNC_IO_WORD = 1; - - do - { - - asm volatile ( "lpsw %0" : : "m" (io_sync_wait) ); -hio_wakeup: - io_parm = *(__u32 *)__LC_IO_INT_PARM; - io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; - - ready = s390_process_IRQ( io_sub ); - - } while ( !((io_sub == irq) && (ready == 1)) ); - - *(__u32 *)__LC_SYNC_IO_WORD = 0; - - } /* endif */ - - ret = 0; - break; - - case 1 : /* status pending */ - - ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING; - - /* - * initialize the device driver specific devstat irb area - */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, - '\0', sizeof( irb_t) ); - - /* - * Let the common interrupt handler process the pending - * status. However, we must avoid calling the user - * action handler, as it won't be prepared to handle - * a pending status during do_IO() processing inline. - * This also implies that s390_process_IRQ must - * terminate synchronously - especially if device - * sensing is required. - */ - ioinfo[irq]->ui.flags.s_pend = 1; - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->ui.flags.doio = 1; - - s390_process_IRQ( irq ); - - ioinfo[irq]->ui.flags.s_pend = 0; - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.doio = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - - ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; - - /* - * In multipath mode a condition code 3 implies the last - * path has gone, except we have previously restricted - * the I/O to a particular path. A condition code 1 - * (0 won't occur) results in return code EIO as well - * as 3 with another path than the one used (i.e. path available mask is non-zero). - */ - if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 ) - { - ret = -ENODEV; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 0; - } - else - { - ret = -EIO; - ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 1; - - } /* endif */ - - break; - - case 2 : /* busy */ - - ret = -EBUSY; - break; - - default: /* device not operational */ - - ret = -ENODEV; - break; - - } /* endswitch */ - - if ( ( flag & DOIO_WAIT_FOR_INTERRUPT ) - && ( sync_isc_locked ) ) - { - sync_isc_locked = 0; // local setting - ioinfo[irq]->ui.flags.syncio = 0; // global setting - - disable_cpu_sync_isc( irq ); - - spin_unlock_irqrestore( &sync_isc, psw_flags); - - } /* endif */ - - } /* endif */ - - return( ret ); -} - -/* - * Note: The "intparm" parameter is not used by the clear_IO() function - * itself, as no ORB is built for the CSCH instruction. However, - * it allows the device interrupt handler to associate the upcoming - * interrupt with the clear_IO() request. - */ -int clear_IO( int irq, - unsigned long user_intparm, - unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */ -{ - int ret; - int ccode; - unsigned long psw_flags; - - int sync_isc_locked = 0; - - if ( irq > highest_subchannel || irq < 0 ) - { - ret = -ENODEV; - } - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* - * we only allow for halt_IO if the device has an I/O handler associated - */ - else if ( !ioinfo[irq]->ui.flags.ready ) - { - ret = -ENODEV; - } - /* - * we ignore the halt_io() request if ending_status was received but - * a SENSE operation is waiting for completion. - */ - else if ( ioinfo[irq]->ui.flags.w4sense ) - { - ret = 0; - } - /* - * We don't allow for halt_io with a sync do_IO() requests pending. - * Concurrent I/O is possible in SMP environments only, but the - * sync. I/O request can be gated to one CPU at a time only. - */ - else if ( ioinfo[irq]->ui.flags.syncio ) - { - ret = -EBUSY; - } - else - { - /* - * If sync processing was requested we lock the sync ISC, - * modify the device to present interrupts for this ISC only - * and switch the CPU to handle this ISC + the console ISC - * exclusively. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - // - // check whether we run recursively (sense processing) - // - if ( !ioinfo[irq]->ui.flags.syncio ) - { - spin_lock_irqsave( &sync_isc, psw_flags); - - ret = enable_cpu_sync_isc( irq); - - if ( ret ) - { - spin_unlock_irqrestore( &sync_isc, - psw_flags); - return( ret); - } - else - { - sync_isc_locked = 1; // local - ioinfo[irq]->ui.flags.syncio = 1; // global - - } /* endif */ - - } /* endif */ - - } /* endif */ - - /* - * Issue "Halt subchannel" and process condition code - */ - ccode = csch( irq ); - - switch ( ccode ) { - case 0: - - ioinfo[irq]->ui.flags.haltio = 1; - - if ( !ioinfo[irq]->ui.flags.doio ) - { - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->u_intparm = user_intparm; - ioinfo[irq]->devstat.cstat = 0; - ioinfo[irq]->devstat.dstat = 0; - ioinfo[irq]->devstat.lpum = 0; - ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION; - ioinfo[irq]->devstat.scnt = 0; - - } - else - { - ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION; - - } /* endif */ - - /* - * If synchronous I/O processing is requested, we have - * to wait for the corresponding interrupt to occur by - * polling the interrupt condition. However, as multiple - * interrupts may be outstanding, we must not just wait - * for the first interrupt, but must poll until ours - * pops up. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - int io_sub; - __u32 io_parm; - psw_t io_new_psw; - int ccode; - - int ready = 0; - struct _lowcore *lc = NULL; - - /* - * We shouldn't perform a TPI loop, waiting for - * an interrupt to occur, but should load a - * WAIT PSW instead. Otherwise we may keep the - * channel subsystem busy, not able to present - * the interrupt. When our sync. interrupt - * arrived we reset the I/O old PSW to its - * original value. - */ - memcpy( &io_new_psw, - &lc->io_new_psw, - sizeof(psw_t)); - - ccode = iac(); - - switch (ccode) { - case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; - break; - case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; - break; - default: - panic( "halt_IO() : unexpected " - "address-space-control %d\n", - ccode); - break; - } /* endswitch */ - - io_sync_wait.addr = FIX_PSW(&&cio_wakeup); - - /* - * Martin didn't like modifying the new PSW, now we take - * a fast exit in do_IRQ() instead - */ - *(__u32 *)__LC_SYNC_IO_WORD = 1; - - do - { - - asm volatile ( "lpsw %0" : : "m" (io_sync_wait) ); -cio_wakeup: - io_parm = *(__u32 *)__LC_IO_INT_PARM; - io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; - - ready = s390_process_IRQ( io_sub ); - - } while ( !((io_sub == irq) && (ready == 1)) ); - - *(__u32 *)__LC_SYNC_IO_WORD = 0; - - } /* endif */ - - ret = 0; - break; - - case 1 : /* status pending */ - - ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING; - - /* - * initialize the device driver specific devstat irb area - */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, - '\0', sizeof( irb_t) ); - - /* - * Let the common interrupt handler process the pending - * status. However, we must avoid calling the user - * action handler, as it won't be prepared to handle - * a pending status during do_IO() processing inline. - * This also implies that s390_process_IRQ must - * terminate synchronously - especially if device - * sensing is required. - */ - ioinfo[irq]->ui.flags.s_pend = 1; - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->ui.flags.doio = 1; - - s390_process_IRQ( irq ); - - ioinfo[irq]->ui.flags.s_pend = 0; - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.doio = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - - ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; - - /* - * In multipath mode a condition code 3 implies the last - * path has gone, except we have previously restricted - * the I/O to a particular path. A condition code 1 - * (0 won't occur) results in return code EIO as well - * as 3 with another path than the one used (i.e. path available mask is non-zero). - */ - if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 ) - { - ret = -ENODEV; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 0; - } - else - { - ret = -EIO; - ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 1; - - } /* endif */ - - break; - - case 2 : /* busy */ - - ret = -EBUSY; - break; - - default: /* device not operational */ - - ret = -ENODEV; - break; - - } /* endswitch */ - - if ( ( flag & DOIO_WAIT_FOR_INTERRUPT ) - && ( sync_isc_locked ) ) - { - sync_isc_locked = 0; // local setting - ioinfo[irq]->ui.flags.syncio = 0; // global setting - - disable_cpu_sync_isc( irq ); - - spin_unlock_irqrestore( &sync_isc, psw_flags); - - } /* endif */ - - } /* endif */ - - return( ret ); -} - - -/* - * do_IRQ() handles all normal I/O device IRQ's (the special - * SMP cross-CPU interrupts have their own specific - * handlers). - * - * Returns: 0 - no ending status received, no further action taken - * 1 - interrupt handler was called with ending status - */ -asmlinkage void do_IRQ( struct pt_regs regs, - unsigned int irq, - __u32 s390_intparm ) -{ -#ifdef CONFIG_FAST_IRQ - int ccode; - tpi_info_t tpi_info; - int new_irq; -#endif - int use_irq = irq; -// __u32 use_intparm = s390_intparm; - - // - // fix me !!! - // - // We need to schedule device recognition, the interrupt stays - // pending. We need to dynamically allocate an ioinfo structure. - // - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return; /* this keeps the device boxed ... */ - } - - /* - * take fast exit if CPU is in sync. I/O state - * - * Note: we have to turn off the WAIT bit and re-disable - * interrupts prior to return as this was the initial - * entry condition to synchronous I/O. - */ - if ( *(__u32 *)__LC_SYNC_IO_WORD ) - { - regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT); - - return; - - } /* endif */ - - s390irq_spin_lock(use_irq); - -#ifdef CONFIG_FAST_IRQ - do { -#endif /* CONFIG_FAST_IRQ */ - - s390_process_IRQ( use_irq ); - -#ifdef CONFIG_FAST_IRQ - - /* - * more interrupts pending ? - */ - ccode = tpi( &tpi_info ); - - if ( ! ccode ) - break; // no, leave ... - - new_irq = tpi_info.irq; -// use_intparm = tpi_info.intparm; - - /* - * if the interrupt is for a different irq we - * release the current irq lock and obtain - * a new one ... - */ - if ( new_irq != use_irq ) - { - s390irq_spin_unlock(use_irq); - use_irq = new_irq; - s390irq_spin_lock(use_irq); - - } /* endif */ - - } while ( 1 ); - -#endif /* CONFIG_FAST_IRQ */ - - s390irq_spin_unlock(use_irq); - - return; -} - -/* - * s390_process_IRQ() handles status pending situations and interrupts - * - * Called by : do_IRQ() - for "real" interrupts - * s390_start_IO, halt_IO() - * - status pending cond. after SSCH, or HSCH - * disable_subchannel() - status pending conditions (after MSCH) - * - * Returns: 0 - no ending status received, no further action taken - * 1 - interrupt handler was called with ending status - */ -int s390_process_IRQ( unsigned int irq ) -{ - int ccode; /* condition code from tsch() operation */ - int irb_cc; /* condition code from irb */ - int sdevstat; /* effective struct devstat size to copy */ - unsigned int fctl; /* function control */ - unsigned int stctl; /* status control */ - unsigned int actl; /* activity control */ - struct irqaction *action; - struct pt_regs regs; /* for interface compatibility only */ - - int issense = 0; - int ending_status = 0; - int allow4handler = 1; - int chnchk = 0; -#if 0 - int cpu = smp_processor_id(); - - kstat.irqs[cpu][irq]++; -#endif - action = ioinfo[irq]->irq_desc.action; - - /* - * It might be possible that a device was not-oper. at the time - * of free_irq() processing. This means the handler is no longer - * available when the device possibly becomes ready again. In - * this case we perform delayed disable_subchannel() processing. - */ - if ( action == NULL ) - { - if ( !ioinfo[irq]->ui.flags.d_disable ) - { - printk( KERN_CRIT"s390_process_IRQ(%04X) " - "- no interrupt handler registered" - "for device %04X !\n", - irq, - ioinfo[irq]->devstat.devno); - - } /* endif */ - - } /* endif */ - - /* - * retrieve the i/o interrupt information (irb), - * update the device specific status information - * and possibly call the interrupt handler. - * - * Note 1: At this time we don't process the resulting - * condition code (ccode) from tsch(), although - * we probably should. - * - * Note 2: Here we will have to check for channel - * check conditions and call a channel check - * handler. - * - * Note 3: If a start function was issued, the interruption - * parameter relates to it. If a halt function was - * issued for an idle device, the intparm must not - * be taken from lowcore, but from the devstat area. - */ - ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) ); - - // - // We must only accumulate the status if initiated by do_IO() or halt_IO() - // - if ( ioinfo[irq]->ui.flags.busy ) - { - ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat; - ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat; - } - else - { - ioinfo[irq]->devstat.dstat = ioinfo[irq]->devstat.ii.irb.scsw.dstat; - ioinfo[irq]->devstat.cstat = ioinfo[irq]->devstat.ii.irb.scsw.cstat; - - ioinfo[irq]->devstat.flag = 0; // reset status flags - - } /* endif */ - - ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum; - - if ( ioinfo[irq]->ui.flags.busy) - { - ioinfo[irq]->devstat.intparm = ioinfo[irq]->u_intparm; - - } /* endif */ - - /* - * reset device-busy bit if no longer set in irb - */ - if ( (ioinfo[irq]->devstat.dstat & DEV_STAT_BUSY ) - && ((ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0)) - { - ioinfo[irq]->devstat.dstat &= ~DEV_STAT_BUSY; - - } /* endif */ - - /* - * Save residual count and CCW information in case primary and - * secondary status are presented with different interrupts. - */ - if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl & SCSW_STCTL_PRIM_STATUS ) - { - ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count; - -#if CONFIG_DEBUG_IO - if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " - "residual count from irb after tsch() %d\n", - irq, ioinfo[irq]->devstat.rescnt ); -#endif - } /* endif */ - - if ( ioinfo[irq]->devstat.ii.irb.scsw.cpa != 0 ) - { - ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa; - - } /* endif */ - - irb_cc = ioinfo[irq]->devstat.ii.irb.scsw.cc; - - // - // check for any kind of channel or interface control check but don't - // issue the message for the console device - // - if ( (ioinfo[irq]->devstat.ii.irb.scsw.cstat - & ( SCHN_STAT_CHN_DATA_CHK - | SCHN_STAT_CHN_CTRL_CHK - | SCHN_STAT_INTF_CTRL_CHK ) ) - && (irq != cons_dev ) ) - { - printk( "Channel-Check or Interface-Control-Check " - "received\n" - " ... device %04X on subchannel %04X, dev_stat " - ": %02X sch_stat : %02X\n", - ioinfo[irq]->devstat.devno, - irq, - ioinfo[irq]->devstat.dstat, - ioinfo[irq]->devstat.cstat); - - chnchk = 1; - - } /* endif */ - - issense = ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.cons; - - if ( issense ) - { - ioinfo[irq]->devstat.scnt = - ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.scnt; - ioinfo[irq]->devstat.flag |= - DEVSTAT_FLAG_SENSE_AVAIL; - - sdevstat = sizeof( devstat_t); - -#if CONFIG_DEBUG_IO - if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " - "concurrent sense bytes avail %d\n", - irq, ioinfo[irq]->devstat.scnt ); -#endif - } - else - { - /* don't copy the sense data area ! */ - sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT; - - } /* endif */ - - switch ( irb_cc ) { - case 1: /* status pending */ - - ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING; - - case 0: /* normal i/o interruption */ - - fctl = ioinfo[irq]->devstat.ii.irb.scsw.fctl; - stctl = ioinfo[irq]->devstat.ii.irb.scsw.stctl; - actl = ioinfo[irq]->devstat.ii.irb.scsw.actl; - - if ( chnchk && (ioinfo[irq]->senseid.cu_type == 0x3088)) - { - char buffer[80]; - - sprintf( buffer, "s390_process_IRQ(%04X) - irb for " - "device %04X after channel check\n", - irq, - ioinfo[irq]->devstat.devno ); - - s390_displayhex( buffer, - &(ioinfo[irq]->devstat.ii.irb) , - sizeof(irb_t)); - } /* endif */ - - ioinfo[irq]->stctl |= stctl; - - ending_status = ( stctl & SCSW_STCTL_SEC_STATUS ) - || ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND) ) - || ( (fctl == SCSW_FCTL_HALT_FUNC) && (stctl == SCSW_STCTL_STATUS_PEND) ); - - /* - * Check for unsolicited interrupts - for debug purposes only - * - * We only consider an interrupt as unsolicited, if the device was not - * actively in use (busy) and an interrupt other than an ALERT status - * was received. - * - * Note: We must not issue a message to the console, if the - * unsolicited interrupt applies to the console device - * itself ! - */ -#if CONFIG_DEBUG_IO - if ( ( irq != cons_dev ) - && !( stctl & SCSW_STCTL_ALERT_STATUS ) - && ( ioinfo[irq]->ui.flags.busy == 0 ) ) - { - char buffer[80]; - - printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n" - " ... device status : %02X subchannel status : %02X\n", - ioinfo[irq]->devstat.devno, - irq, - ioinfo[irq]->devstat.dstat, - ioinfo[irq]->devstat.cstat); - - sprintf( buffer, "s390_process_IRQ(%04X) - irb for " - "device %04X, ending_status %d\n", - irq, - ioinfo[irq]->devstat.devno, - ending_status); - - s390_displayhex( buffer, - &(ioinfo[irq]->devstat.ii.irb) , - sizeof(irb_t)); - - } /* endif */ - - /* - * take fast exit if no handler is available - */ - if ( !action ) - return( ending_status ); - -#endif - /* - * Check whether we must issue a SENSE CCW ourselves if there is no - * concurrent sense facility installed for the subchannel. - * - * Note: We should check for ioinfo[irq]->ui.flags.consns but VM - * violates the ESA/390 architecture and doesn't present an - * operand exception for virtual devices without concurrent - * sense facility available/supported when enabling the - * concurrent sense facility. - */ - if ( ( ( ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK ) - && ( !issense ) ) - || ( ioinfo[irq]->ui.flags.delsense && ending_status ) ) - { - int ret_io; - ccw1_t *s_ccw = &ioinfo[irq]->senseccw; - unsigned long s_flag = 0; - - if ( ending_status ) - { - /* - * We copy the current status information into the device driver - * status area. Then we can use the local devstat area for device - * sensing. When finally calling the IRQ handler we must not overlay - * the original device status but copy the sense data only. - */ - memcpy( action->dev_id, - &(ioinfo[irq]->devstat), - sizeof( devstat_t) ); - - s_ccw->cmd_code = CCW_CMD_BASIC_SENSE; - s_ccw->cda = (__u32)virt_to_phys( ioinfo[irq]->devstat.ii.sense.data); - s_ccw->count = SENSE_MAX_COUNT; - s_ccw->flags = CCW_FLAG_SLI; - - /* - * If free_irq() or a sync do_IO/s390_start_IO() is in - * process we have to sense synchronously - */ - if ( ioinfo[irq]->ui.flags.unready || ioinfo[irq]->ui.flags.syncio ) - { - s_flag = DOIO_WAIT_FOR_INTERRUPT; - - } /* endif */ - - /* - * Reset status info - * - * It does not matter whether this is a sync. or async. - * SENSE request, but we have to assure we don't call - * the irq handler now, but keep the irq in busy state. - * In sync. mode s390_process_IRQ() is called recursively, - * while in async. mode we re-enter do_IRQ() with the - * next interrupt. - * - * Note : this may be a delayed sense request ! - */ - allow4handler = 0; - - ioinfo[irq]->ui.flags.fast = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - ioinfo[irq]->ui.flags.delsense = 0; - - ioinfo[irq]->devstat.cstat = 0; - ioinfo[irq]->devstat.dstat = 0; - ioinfo[irq]->devstat.rescnt = SENSE_MAX_COUNT; - - ioinfo[irq]->ui.flags.w4sense = 1; - - ret_io = s390_start_IO( irq, - s_ccw, - 0xE2C5D5E2, // = SENSe - 0, // n/a - s_flag); - } - else - { - /* - * we received an Unit Check but we have no final - * status yet, therefore we must delay the SENSE - * processing. However, we must not report this - * intermediate status to the device interrupt - * handler. - */ - ioinfo[irq]->ui.flags.fast = 0; - ioinfo[irq]->ui.flags.repall = 0; - - ioinfo[irq]->ui.flags.delsense = 1; - allow4handler = 0; - - } /* endif */ - - } /* endif */ - - /* - * we allow for the device action handler if . - * - we received ending status - * - the action handler requested to see all interrupts - * - we received a PCI - * - fast notification was requested (primary status) - * - unsollicited interrupts - * - */ - if ( allow4handler ) - { - allow4handler = ending_status - || ( ioinfo[irq]->ui.flags.repall ) - || ( ioinfo[irq]->devstat.ii.irb.scsw.cstat & SCHN_STAT_PCI ) - || ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) ) - || ( ioinfo[irq]->ui.flags.oper == 0 ); - - } /* endif */ - - /* - * We used to copy the device status information right before - * calling the device action handler. However, in status - * pending situations during do_IO() or halt_IO(), as well as - * enable_subchannel/disable_subchannel processing we must - * synchronously return the status information and must not - * call the device action handler. - * - */ - if ( allow4handler ) - { - /* - * if we were waiting for sense data we copy the sense - * bytes only as the original status information was - * saved prior to sense already. - */ - if ( ioinfo[irq]->ui.flags.w4sense ) - { - int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt; - -#if CONFIG_DEBUG_IO - if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " - "BASIC SENSE bytes avail %d\n", - irq, sense_count ); -#endif - ioinfo[irq]->ui.flags.w4sense = 0; - ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FLAG_SENSE_AVAIL; - ((devstat_t *)(action->dev_id))->scnt = sense_count; - - if ( sense_count >= 0 ) - { - memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data, - &(ioinfo[irq]->devstat.ii.sense.data), - sense_count); - } - else - { -#if 1 - panic( "s390_process_IRQ(%04x) encountered " - "negative sense count\n", - irq); -#else - printk( KERN_CRIT"s390_process_IRQ(%04x) encountered " - "negative sense count\n", - irq); -#endif - } /* endif */ - } - else - { - memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat ); - - } /* endif */ - - } /* endif */ - - /* - * for status pending situations other than deferred interrupt - * conditions detected by s390_process_IRQ() itself we must not - * call the handler. This will synchronously be reported back - * to the caller instead, e.g. when detected during do_IO(). - */ - if ( ioinfo[irq]->ui.flags.s_pend || ioinfo[irq]->ui.flags.unready ) - allow4handler = 0; - - /* - * Call device action handler if applicable - */ - if ( allow4handler ) - { - - /* - * We only reset the busy condition when we are sure that no further - * interrupt is pending for the current I/O request (ending_status). - */ - if ( ending_status || !ioinfo[irq]->ui.flags.oper ) - { - ioinfo[irq]->ui.flags.oper = 1; /* dev IS oper */ - - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.doio = 0; - ioinfo[irq]->ui.flags.haltio = 0; - ioinfo[irq]->ui.flags.fast = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - - ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; - ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FINAL_STATUS; - - action->handler( irq, action->dev_id, ®s); - - // - // reset intparm after final status or we will badly present unsolicited - // interrupts with a intparm value possibly no longer valid. - // - ioinfo[irq]->devstat.intparm = 0; - - // - // Was there anything queued ? Start the pending channel program - // if there is one. - // - if ( ioinfo[irq]->ui.flags.doio_q ) - { - int ret; - - ret = s390_start_IO( irq, - ioinfo[irq]->qcpa, - ioinfo[irq]->qintparm, - ioinfo[irq]->qlpm, - ioinfo[irq]->qflag); - - ioinfo[irq]->ui.flags.doio_q = 0; - - /* - * If s390_start_IO() failed call the device's interrupt - * handler, the IRQ related devstat area was setup by - * s390_start_IO() accordingly already (status pending - * condition). - */ - if ( ret ) - { - action->handler( irq, action->dev_id, ®s); - - } /* endif */ - - } /* endif */ - - } - else - { - ioinfo[irq]->ui.flags.w4final = 1; - action->handler( irq, action->dev_id, ®s); - - } /* endif */ - - } /* endif */ - - break; - - case 3: /* device not operational */ - - ioinfo[irq]->ui.flags.oper = 0; - - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.doio = 0; - ioinfo[irq]->ui.flags.haltio = 0; - - ioinfo[irq]->devstat.cstat = 0; - ioinfo[irq]->devstat.dstat = 0; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; - - /* - * When we find a device "not oper" we save the status - * information into the device status area and call the - * device specific interrupt handler. - * - * Note: currently we don't have any way to reenable - * the device unless an unsolicited interrupt - * is presented. We don't check for spurious - * interrupts on "not oper" conditions. - */ - - if ( ( ioinfo[irq]->ui.flags.fast ) - && ( ioinfo[irq]->ui.flags.w4final ) ) - { - /* - * If a new request was queued already, we have - * to simulate the "not oper" status for the - * queued request by switching the "intparm" value - * and notify the interrupt handler. - */ - if ( ioinfo[irq]->ui.flags.doio_q ) - { - ioinfo[irq]->devstat.intparm = ioinfo[irq]->qintparm; - - } /* endif */ - - } /* endif */ - - ioinfo[irq]->ui.flags.fast = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - - memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat ); - - ioinfo[irq]->devstat.intparm = 0; - - if ( !ioinfo[irq]->ui.flags.s_pend ) - action->handler( irq, action->dev_id, ®s); - - ending_status = 1; - - break; - - } /* endswitch */ - - return( ending_status ); -} - -/* - * Set the special i/o-interruption sublass 7 for the - * device specified by parameter irq. There can only - * be a single device been operated on this special - * isc. This function is aimed being able to check - * on special device interrupts in disabled state, - * without having to delay I/O processing (by queueing) - * for non-console devices. - * - * Setting of this isc is done by set_cons_dev(), while - * reset_cons_dev() resets this isc and re-enables the - * default isc3 for this device. wait_cons_dev() allows - * to actively wait on an interrupt for this device in - * disabed state. When the interrupt condition is - * encountered, wait_cons_dev(9 calls do_IRQ() to have - * the console device driver processing the interrupt. - */ -int set_cons_dev( int irq ) -{ - int ccode; - unsigned long cr6 __attribute__ ((aligned (8))); - int rc = 0; - - if ( cons_dev != -1 ) - { - rc = -EBUSY; - } - else if ( (irq > highest_subchannel) || (irq < 0) ) - { - rc = -ENODEV; - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - else - { - /* - * modify the indicated console device to operate - * on special console interrupt sublass 7 - */ - ccode = stsch( irq, &(ioinfo[irq]->schib) ); - - if (ccode) - { - rc = -ENODEV; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - } - else - { - ioinfo[irq]->schib.pmcw.isc = 7; - - ccode = msch( irq, &(ioinfo[irq]->schib) ); - - if (ccode) - { - rc = -EIO; - } - else - { - cons_dev = irq; - - /* - * enable console I/O-interrupt sublass 7 - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - cr6 |= 0x01000000; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - } /* endif */ - - } /* endif */ - - } /* endif */ - - return( rc); -} - -int reset_cons_dev( int irq) -{ - int rc = 0; - int ccode; - long cr6 __attribute__ ((aligned (8))); - - if ( cons_dev != -1 ) - { - rc = -EBUSY; - } - else if ( (irq > highest_subchannel) || (irq < 0) ) - { - rc = -ENODEV; - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - else - { - /* - * reset the indicated console device to operate - * on default console interrupt sublass 3 - */ - ccode = stsch( irq, &(ioinfo[irq]->schib) ); - - if (ccode) - { - rc = -ENODEV; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - } - else - { - - ioinfo[irq]->schib.pmcw.isc = 3; - - ccode = msch( irq, &(ioinfo[irq]->schib) ); - - if (ccode) - { - rc = -EIO; - } - else - { - cons_dev = -1; - - /* - * disable special console I/O-interrupt sublass 7 - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - cr6 &= 0xFEFFFFFF; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - } /* endif */ - - } /* endif */ - - } /* endif */ - - return( rc); -} - -int wait_cons_dev( int irq ) -{ - int rc = 0; - long save_cr6; - - if ( irq == cons_dev ) - { - - /* - * before entering the spinlock we may already have - * processed the interrupt on a different CPU ... - */ - if ( ioinfo[irq]->ui.flags.busy == 1 ) - { - long cr6 __attribute__ ((aligned (8))); - - /* - * disable all, but isc 7 (console device) - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - save_cr6 = cr6; - cr6 &= 0x01FFFFFF; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - do { - tpi_info_t tpi_info; - if (tpi(&tpi_info) == 1) { - s390_process_IRQ( tpi_info.irq ); - } else { - s390irq_spin_unlock(irq); - tod_wait(100); - s390irq_spin_lock(irq); - } - eieio(); - } while (ioinfo[irq]->ui.flags.busy == 1); - - /* - * restore previous isc value - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - cr6 = save_cr6; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - } /* endif */ - - } - else - { - rc = EINVAL; - - } /* endif */ - - - return(rc); -} - - -int enable_cpu_sync_isc( int irq ) -{ - int ccode; - long cr6 __attribute__ ((aligned (8))); - - int count = 0; - int rc = 0; - - if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA ) - { - ccode = stsch( irq, &(ioinfo[irq]->schib) ); - - if ( !ccode ) - { - ioinfo[irq]->schib.pmcw.isc = 5; - - do - { - ccode = msch( irq, &(ioinfo[irq]->schib) ); - - if (ccode == 0 ) - { - /* - * enable interrupt subclass in CPU - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - cr6 |= 0x04000000; // enable sync isc 5 - cr6 &= 0xEFFFFFFF; // disable standard isc 3 - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - } - else if (ccode == 3) - { - rc = -ENODEV; // device not-oper - very unlikely - - } - else if (ccode == 2) - { - rc = -EBUSY; // device busy - should not happen - - } - else if (ccode == 1) - { - // - // process pending status - // - ioinfo[irq]->ui.flags.s_pend = 1; - - s390_process_IRQ( irq ); - - ioinfo[irq]->ui.flags.s_pend = 0; - - count++; - - } /* endif */ - - } while ( ccode == 1 && count < 3 ); - - if ( count == 3) - { - rc = -EIO; - - } /* endif */ - } - else - { - rc = -ENODEV; // device is not-operational - - } /* endif */ - } - else - { - rc = -EINVAL; - - } /* endif */ - - return( rc); -} - -int disable_cpu_sync_isc( int irq) -{ - int rc = 0; - int ccode; - long cr6 __attribute__ ((aligned (8))); - - if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA ) - { - ccode = stsch( irq, &(ioinfo[irq]->schib) ); - - ioinfo[irq]->schib.pmcw.isc = 3; - - ccode = msch( irq, &(ioinfo[irq]->schib) ); - - if (ccode) - { - rc = -EIO; - } - else - { - - /* - * enable interrupt subclass in CPU - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - cr6 &= 0xFBFFFFFF; // disable sync isc 5 - cr6 |= 0x10000000; // enable standard isc 3 - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - } /* endif */ - - } - else - { - rc = -EINVAL; - - } /* endif */ - - return( rc); -} - -// -// Input : -// devno - device number -// ps - pointer to sense ID data area -// -// Output : none -// -void VM_virtual_device_info( __u16 devno, - senseid_t *ps ) -{ - diag210_t diag_data; - int ccode; - - int error = 0; - - diag_data.vrdcdvno = devno; - diag_data.vrdclen = sizeof( diag210_t); - ccode = diag210( (diag210_t *)virt_to_phys( &diag_data ) ); - ps->reserved = 0xff; - - switch (diag_data.vrdcvcla) { - case 0x80: - - switch (diag_data.vrdcvtyp) { - case 00: - - ps->cu_type = 0x3215; - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - break; - - case 0x40: - - switch (diag_data.vrdcvtyp) { - case 0xC0: - - ps->cu_type = 0x5080; - - break; - - case 0x80: - - ps->cu_type = 0x2250; - - break; - - case 0x04: - - ps->cu_type = 0x3277; - - break; - - case 0x01: - - ps->cu_type = 0x3278; - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - break; - - case 0x20: - - switch (diag_data.vrdcvtyp) { - case 0x84: - - ps->cu_type = 0x3505; - - break; - - case 0x82: - - ps->cu_type = 0x2540; - - break; - - case 0x81: - - ps->cu_type = 0x2501; - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - break; - - case 0x10: - - switch (diag_data.vrdcvtyp) { - case 0x84: - - ps->cu_type = 0x3525; - - break; - - case 0x82: - - ps->cu_type = 0x2540; - - break; - - case 0x4F: - case 0x4E: - case 0x48: - - ps->cu_type = 0x3820; - - break; - - case 0x4D: - case 0x49: - case 0x45: - - ps->cu_type = 0x3800; - - break; - - case 0x4B: - - ps->cu_type = 0x4248; - - break; - - case 0x4A: - - ps->cu_type = 0x4245; - - break; - - case 0x47: - - ps->cu_type = 0x3262; - - break; - - case 0x43: - - ps->cu_type = 0x3203; - - break; - - case 0x42: - - ps->cu_type = 0x3211; - - break; - - case 0x41: - - ps->cu_type = 0x1403; - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - break; - - case 0x08: - - switch (diag_data.vrdcvtyp) { - case 0x82: - - ps->cu_type = 0x3422; - - break; - - case 0x81: - - ps->cu_type = 0x3490; - - break; - - case 0x10: - - ps->cu_type = 0x3420; - - break; - - case 0x02: - - ps->cu_type = 0x3430; - - break; - - case 0x01: - - ps->cu_type = 0x3480; - - break; - - case 0x42: - - ps->cu_type = 0x3424; - - break; - - case 0x44: - - ps->cu_type = 0x9348; - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - if ( error ) - {printk( "DIAG X'210' for device %04X returned (cc = %d): vdev class : %02X, " - "vdev type : %04X \n ... rdev class : %02X, rdev type : %04X, rdev model: %02X\n", - devno, - ccode, - diag_data.vrdcvcla, - diag_data.vrdcvtyp, - diag_data.vrdcrccl, - diag_data.vrdccrty, - diag_data.vrdccrmd ); - - } /* endif */ - -} - -/* - * This routine returns the characteristics for the device - * specified. Some old devices might not provide the necessary - * command code information during SenseID processing. In this - * case the function returns -EINVAL. Otherwise the function - * allocates a decice specific data buffer and provides the - * device characteristics together with the buffer size. Its - * the callers responability to release the kernel memory if - * not longer needed. In case of persistent I/O problems -EBUSY - * is returned. - * - * The function may be called enabled or disabled. However, the - * caller must have locked the irq it is requesting data for. - * - * Note : It would have been nice to collect this information - * during init_IRQ() processing but this is not possible - * - * a) without statically pre-allocation fixed size buffers - * as virtual memory management isn't available yet. - * - * b) without unnecessarily increase system startup by - * evaluating devices eventually not used at all. - */ -int read_dev_chars( int irq, void **buffer, int length ) -{ - unsigned int flags; - ccw1_t *rdc_ccw; - devstat_t devstat; - char *rdc_buf; - int devflag; - - int ret = 0; - int emulated = 0; - int retry = 5; - - if ( !buffer || !length ) - { - return( -EINVAL ); - - } /* endif */ - - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); - - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); - - } /* endif */ - - /* - * Before playing around with irq locks we should assure - * running disabled on (just) our CPU. Sync. I/O requests - * also require to run disabled. - * - * Note : as no global lock is required, we must not use - * cli(), but __cli() instead. - */ - __save_flags(flags); - __cli(); - - rdc_ccw = &ioinfo[irq]->senseccw; - - if ( !ioinfo[irq]->ui.flags.ready ) - { - ret = request_irq( irq, - init_IRQ_handler, - 0, "RDC", &devstat ); - - if ( !ret ) - { - emulated = 1; - - } /* endif */ - - } /* endif */ - - if ( !ret ) - { - if ( ! *buffer ) - { - rdc_buf = kmalloc( length, GFP_KERNEL); - } - else - { - rdc_buf = *buffer; - - } /* endif */ - - if ( !rdc_buf ) - { - ret = -ENOMEM; - } - else - { - do - { - rdc_ccw->cmd_code = CCW_CMD_RDC; - rdc_ccw->cda = (__u32)virt_to_phys( rdc_buf ); - rdc_ccw->count = length; - rdc_ccw->flags = CCW_FLAG_SLI; - - ret = s390_start_IO( irq, - rdc_ccw, - 0x00524443, // RDC - 0, // n/a - DOIO_WAIT_FOR_INTERRUPT ); - retry--; - devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag; - - } while ( ( retry ) - && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) ); - - } /* endif */ - - if ( !retry ) - { - ret = -EBUSY; - - } /* endif */ - - __restore_flags(flags); - - /* - * on success we update the user input parms - */ - if ( !ret ) - { - *buffer = rdc_buf; - - } /* endif */ - - if ( emulated ) - { - free_irq( irq, &devstat); - - } /* endif */ - - } /* endif */ - - return( ret ); -} - -/* - * Read Configuration data - */ -int read_conf_data( int irq, void **buffer, int *length ) -{ - int found = 0; - int ciw_cnt = 0; - unsigned int flags; - - int ret = 0; - - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - - } /* endif */ - - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); - - } /* endif */ - - /* - * scan for RCD command in extended SenseID data - */ - for ( ; (found == 0) && (ciw_cnt < 62); ciw_cnt++ ) - { - if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD ) - { - found = 1; - break; - } /* endif */ - - } /* endfor */ - - if ( found ) - { - ccw1_t *rcd_ccw = &ioinfo[irq]->senseccw; - devstat_t devstat; - char *rcd_buf; - int devflag; - - int emulated = 0; - int retry = 5; - - __save_flags(flags); - __cli(); - - if ( !ioinfo[irq]->ui.flags.ready ) - { - ret = request_irq( irq, - init_IRQ_handler, - 0, "RCD", &devstat ); - - if ( !ret ) - { - emulated = 1; - - } /* endif */ - - } /* endif */ - - if ( !ret ) - { - rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count, - GFP_KERNEL); - - do - { - rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd; - rcd_ccw->cda = (__u32)virt_to_phys( rcd_buf ); - rcd_ccw->count = ioinfo[irq]->senseid.ciw[ciw_cnt].count; - rcd_ccw->flags = CCW_FLAG_SLI; - - ret = s390_start_IO( irq, - rcd_ccw, - 0x00524344, // == RCD - 0, // n/a - DOIO_WAIT_FOR_INTERRUPT ); - - retry--; - - devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag; - - } while ( ( retry ) - && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) ); - - if ( !retry ) - ret = -EBUSY; - - __restore_flags(flags); - - } /* endif */ - - /* - * on success we update the user input parms - */ - if ( !ret ) - { - *length = ioinfo[irq]->senseid.ciw[ciw_cnt].count; - *buffer = rcd_buf; - - } /* endif */ - - if ( emulated ) - free_irq( irq, &devstat); - } - else - { - ret = -EINVAL; - - } /* endif */ - - return( ret ); - -} - -int get_dev_info( int irq, dev_info_t * pdi) -{ - return( get_dev_info_by_irq( irq, pdi)); -} - -static int __inline__ get_next_available_irq( ioinfo_t *pi) -{ - int ret_val; - - while ( TRUE ) - { - if ( pi->ui.flags.oper ) - { - ret_val = pi->irq; - break; - } - else - { - pi = pi->next; - - // - // leave at end of list unconditionally - // - if ( pi == NULL ) - { - ret_val = -ENODEV; - break; - } - - } /* endif */ - - } /* endwhile */ - - return ret_val; -} - - -int get_irq_first( void ) -{ - int ret_irq; - - if ( ioinfo_head ) - { - if ( ioinfo_head->ui.flags.oper ) - { - ret_irq = ioinfo_head->irq; - } - else if ( ioinfo_head->next ) - { - ret_irq = get_next_available_irq( ioinfo_head->next ); - - } - else - { - ret_irq = -ENODEV; - - } /* endif */ - } - else - { - ret_irq = -ENODEV; - - } /* endif */ - - return ret_irq; -} - -int get_irq_next( int irq ) -{ - int ret_irq; - - if ( ioinfo[irq] != INVALID_STORAGE_AREA ) - { - if ( ioinfo[irq]->next ) - { - if ( ioinfo[irq]->next->ui.flags.oper ) - { - ret_irq = ioinfo[irq]->next->irq; - } - else - { - ret_irq = get_next_available_irq( ioinfo[irq]->next ); - - } /* endif */ - } - else - { - ret_irq = -ENODEV; - - } /* endif */ - } - else - { - ret_irq = -EINVAL; - - } /* endif */ - - return ret_irq; -} - -int get_dev_info_by_irq( int irq, dev_info_t *pdi) -{ - - if ( irq > highest_subchannel || irq < 0 ) - { - return -ENODEV; - } - else if ( pdi == NULL ) - { - return -EINVAL; - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - else - { - pdi->devno = ioinfo[irq]->schib.pmcw.dev; - pdi->irq = irq; - - if ( ioinfo[irq]->ui.flags.oper ) - { - pdi->status = 0; - memcpy( &(pdi->sid_data), - &ioinfo[irq]->senseid, - sizeof( senseid_t)); - } - else - { - pdi->status = DEVSTAT_NOT_OPER; - memcpy( &(pdi->sid_data), - '\0', - sizeof( senseid_t)); - pdi->sid_data.cu_type = 0xFFFF; - - } /* endif */ - - if ( ioinfo[irq]->ui.flags.ready ) - pdi->status |= DEVSTAT_DEVICE_OWNED; - - return 0; - - } /* endif */ - -} - - -int get_dev_info_by_devno( __u16 devno, dev_info_t *pdi) -{ - int i; - int rc = -ENODEV; - - if ( devno > 0x0000ffff ) - { - return -ENODEV; - } - else if ( pdi == NULL ) - { - return -EINVAL; - } - else - { - - for ( i=0; i <= highest_subchannel; i++ ) - { - - if ( ioinfo[i] != INVALID_STORAGE_AREA - && ioinfo[i]->schib.pmcw.dev == devno ) - { - if ( ioinfo[i]->ui.flags.oper ) - { - pdi->status = 0; - pdi->irq = i; - pdi->devno = devno; - - memcpy( &(pdi->sid_data), - &ioinfo[i]->senseid, - sizeof( senseid_t)); - } - else - { - pdi->status = DEVSTAT_NOT_OPER; - pdi->irq = i; - pdi->devno = devno; - - memcpy( &(pdi->sid_data), '\0', sizeof( senseid_t)); - pdi->sid_data.cu_type = 0xFFFF; - - } /* endif */ - - if ( ioinfo[i]->ui.flags.ready ) - pdi->status |= DEVSTAT_DEVICE_OWNED; - - rc = 0; /* found */ - break; - - } /* endif */ - - } /* endfor */ - - return( rc); - - } /* endif */ - -} - -int get_irq_by_devno( __u16 devno ) -{ - int i; - int rc = -1; - - if ( devno <= 0x0000ffff ) - { - for ( i=0; i <= highest_subchannel; i++ ) - { - if ( (ioinfo[i] != INVALID_STORAGE_AREA ) - && (ioinfo[i]->schib.pmcw.dev == devno) - && (ioinfo[i]->schib.pmcw.dnv == 1 ) ) - { - rc = i; - break; - - } /* endif */ - - } /* endfor */ - - } /* endif */ - - return( rc); -} - -unsigned int get_devno_by_irq( int irq ) -{ - - if ( ( irq > highest_subchannel ) - || ( irq < 0 ) - || ( ioinfo[irq] == INVALID_STORAGE_AREA ) ) - { - return -1; - - } /* endif */ - - /* - * we don't need to check for the device be operational - * as the initial STSCH will always present the device - * number defined by the IOCDS regardless of the device - * existing or not. However, there could be subchannels - * defined who's device number isn't valid ... - */ - if ( ioinfo[irq]->schib.pmcw.dnv ) - return( ioinfo[irq]->schib.pmcw.dev ); - else - return -1; -} - -/* - * s390_device_recognition - * - * Used for system wide device recognition. Issues the device - * independant SenseID command to obtain info the device type. - * - */ -void s390_device_recognition( void) -{ - - int irq = 0; /* let's start with subchannel 0 ... */ - - do - { - /* - * We issue the SenseID command on I/O subchannels we think are - * operational only. - */ - if ( ( ioinfo[irq] != INVALID_STORAGE_AREA ) - && ( ioinfo[irq]->schib.pmcw.st == 0 ) - && ( ioinfo[irq]->ui.flags.oper == 1 ) ) - { - s390_SenseID( irq, &ioinfo[irq]->senseid ); - - } /* endif */ - - irq ++; - - } while ( irq <= highest_subchannel ); - -} - - -/* - * s390_search_devices - * - * Determines all subchannels available to the system. - * - */ -void s390_process_subchannels( void) -{ - int isValid; - int irq = 0; /* Evaluate all subchannels starting with 0 ... */ - - do - { - isValid = s390_validate_subchannel( irq); - - irq++; - - } while ( isValid && irq < __MAX_SUBCHANNELS ); - - highest_subchannel = --irq; - - printk( "\nHighest subchannel number detected: %u\n", - highest_subchannel); -} - -/* - * s390_validate_subchannel() - * - * Process the subchannel for the requested irq. Returns 1 for valid - * subchannels, otherwise 0. - */ -int s390_validate_subchannel( int irq ) -{ - - int retry; /* retry count for status pending conditions */ - int ccode; /* condition code for stsch() only */ - int ccode2; /* condition code for other I/O routines */ - schib_t *p_schib; - - /* - * The first subchannel that is not-operational (ccode==3) - * indicates that there aren't any more devices available. - */ - if ( ( init_IRQ_complete ) - && ( ioinfo[irq] != INVALID_STORAGE_AREA ) ) - { - p_schib = &ioinfo[irq]->schib; - } - else - { - p_schib = &init_schib; - - } /* endif */ - - ccode = stsch( irq, p_schib); - - if ( ccode == 0) - { - /* - * ... just being curious we check for non I/O subchannels - */ - if ( p_schib->pmcw.st ) - { - printk( "Subchannel %04X reports " - "non-I/O subchannel type %04X\n", - irq, - p_schib->pmcw.st); - - if ( ioinfo[irq] != INVALID_STORAGE_AREA ) - ioinfo[irq]->ui.flags.oper = 0; - - } /* endif */ - - if ( p_schib->pmcw.dnv ) - { - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - - if ( !init_IRQ_complete ) - { - ioinfo[irq] = - (ioinfo_t *)alloc_bootmem( sizeof(ioinfo_t)); - } - else - { - ioinfo[irq] = - (ioinfo_t *)kmalloc( sizeof(ioinfo_t), - GFP_KERNEL ); - - } /* endif */ - - memset( ioinfo[irq], '\0', sizeof( ioinfo_t)); - memcpy( &ioinfo[irq]->schib, - &init_schib, - sizeof( schib_t)); - ioinfo[irq]->irq_desc.status = IRQ_DISABLED; - ioinfo[irq]->irq_desc.handler = &no_irq_type; - - /* - * We have to insert the new ioinfo element - * into the linked list, either at its head, - * its tail or insert it. - */ - if ( ioinfo_head == NULL ) /* first element */ - { - ioinfo_head = ioinfo[irq]; - ioinfo_tail = ioinfo[irq]; - } - else if ( irq < ioinfo_head->irq ) /* new head */ - { - ioinfo[irq]->next = ioinfo_head; - ioinfo_head->prev = ioinfo[irq]; - ioinfo_head = ioinfo[irq]; - } - else if ( irq > ioinfo_tail->irq ) /* new tail */ - { - ioinfo_tail->next = ioinfo[irq]; - ioinfo[irq]->prev = ioinfo_tail; - ioinfo_tail = ioinfo[irq]; - } - else /* insert element */ - { - ioinfo_t *pi = ioinfo_head; - - do - { - if ( irq < pi->next->irq ) - { - ioinfo[irq]->next = pi->next; - ioinfo[irq]->prev = pi; - pi->next->prev = ioinfo[irq]; - pi->next = ioinfo[irq]; - break; - - } /* endif */ - - pi = pi->next; - - } while ( 1 ); - - } /* endif */ - - } /* endif */ - - // initialize some values ... - ioinfo[irq]->ui.flags.pgid_supp = 1; - - ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pam - & ioinfo[irq]->schib.pmcw.pom; - - printk( "Detected device %04X on subchannel %04X" - " - PIM = %02X, PAM = %02X, POM = %02X\n", - ioinfo[irq]->schib.pmcw.dev, - irq, - ioinfo[irq]->schib.pmcw.pim, - ioinfo[irq]->schib.pmcw.pam, - ioinfo[irq]->schib.pmcw.pom); - - /* - * We should have at least one CHPID ... - */ - if ( ioinfo[irq]->schib.pmcw.pim - & ioinfo[irq]->schib.pmcw.pam - & ioinfo[irq]->schib.pmcw.pom ) - { - ioinfo[irq]->ui.flags.oper = 0; - - /* - * We now have to initially ... - * ... set "interruption sublass" - * ... enable "concurrent sense" - * ... enable "multipath mode" if more than one - * CHPID is available. This is done regardless - * whether multiple paths are available for us. - * - * Note : we don't enable the device here, this is temporarily - * done during device sensing below. - */ - ioinfo[irq]->schib.pmcw.isc = 3; /* could be smth. else */ - ioinfo[irq]->schib.pmcw.csense = 1; /* concurrent sense */ - ioinfo[irq]->schib.pmcw.ena = 0; /* force disable it */ - ioinfo[irq]->schib.pmcw.intparm = - ioinfo[irq]->schib.pmcw.dev; - - if ( ( ioinfo[irq]->schib.pmcw.pim != 0 ) - && ( ioinfo[irq]->schib.pmcw.pim != 0x80 ) ) - { - ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */ - - } /* endif */ - - /* - * initialize ioinfo structure - */ - ioinfo[irq]->irq = irq; - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.ready = 0; - ioinfo[irq]->ui.flags.oper = 1; - ioinfo[irq]->devstat.intparm = 0; - ioinfo[irq]->devstat.devno = ioinfo[irq]->schib.pmcw.dev; - - retry = 5; - - do - { - ccode2 = msch_err( irq, &ioinfo[irq]->schib); - - switch (ccode2) { - case 0: // successful completion - // - // concurrent sense facility available ... - // - ioinfo[irq]->ui.flags.consns = 1; - break; - - case 1: // status pending - // - // How can we have a pending status as device is - // disabled for interrupts ? Anyway, clear it ... - // - tsch( irq, &(ioinfo[irq]->devstat.ii.irb) ); - retry--; - break; - - case 2: // busy - retry--; - break; - - case 3: // not operational - ioinfo[irq]->ui.flags.oper = 0; - retry = 0; - break; - - default: -#define PGMCHK_OPERAND_EXC 0x15 - - if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC ) - { - /* - * re-issue the modify subchannel without trying to - * enable the concurrent sense facility - */ - ioinfo[irq]->schib.pmcw.csense = 0; - - ccode2 = msch_err( irq, &ioinfo[irq]->schib); - - if ( ccode2 != 0 ) - { - printk( " ... modify subchannel (2) failed with CC = %X\n", - ccode2 ); - ioinfo[irq]->ui.flags.oper = 0; - } - else - { - ioinfo[irq]->ui.flags.consns = 0; - - } /* endif */ - } - else - { - printk( " ... modify subchannel (1) failed with CC = %X\n", - ccode2); - ioinfo[irq]->ui.flags.oper = 0; - - } /* endif */ - - retry = 0; - break; - - } /* endswitch */ - - } while ( ccode2 && retry ); - - if ( (ccode2 < 3) && (!retry) ) - { - printk( " ... msch() retry count for " - "subchannel %04X exceeded, CC = %d\n", - irq, - ccode2); - - } /* endif */ - - } - else - { - ioinfo[irq]->ui.flags.oper = 0; - - } /* endif */ - - } /* endif */ - - } /* endif */ - - /* - * indicate whether the subchannel is valid - */ - if ( ccode == 3) - return(0); - else - return(1); -} - -/* - * s390_SenseID - * - * Try to obtain the 'control unit'/'device type' information - * associated with the subchannel. - * - * The function is primarily meant to be called without irq - * action handler in place. However, it also allows for - * use with an action handler in place. If there is already - * an action handler registered assure it can handle the - * s390_SenseID() related device interrupts - interruption - * parameter used is 0x00E2C9C4 ( SID ). - */ -int s390_SenseID( int irq, senseid_t *sid ) -{ - ccw1_t sense_ccw; /* ccw area for SenseID command */ - devstat_t devstat; /* required by request_irq() */ - - int irq_ret = 0; /* return code */ - int retry = 5; /* retry count */ - int inlreq = 0; /* inline request_irq() */ - - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); - - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } /* endif */ - - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( !ioinfo[irq]->ui.flags.ready ) - { - /* - * Perform SENSE ID command processing. We have to request device - * ownership and provide a dummy I/O handler. We issue sync. I/O - * requests and evaluate the devstat area on return therefore - * we don't need a real I/O handler in place. - */ - irq_ret = request_irq( irq, init_IRQ_handler, 0, "SID", &devstat); - - if ( irq_ret == 0 ) - inlreq = 1; - - } /* endif */ - - if ( irq_ret == 0 ) - { - s390irq_spin_lock( irq); - - sense_ccw.cmd_code = CCW_CMD_SENSE_ID; - sense_ccw.cda = (__u32)virt_to_phys( sid ); - sense_ccw.count = sizeof( senseid_t); - sense_ccw.flags = CCW_FLAG_SLI; - - ioinfo[irq]->senseid.cu_type = 0xFFFF; /* initialize fields ... */ - ioinfo[irq]->senseid.cu_model = 0; - ioinfo[irq]->senseid.dev_type = 0; - ioinfo[irq]->senseid.dev_model = 0; - - /* - * We now issue a SenseID request. In case of BUSY - * or STATUS PENDING conditions we retry 5 times. - */ - do - { - memset( &devstat, '\0', sizeof( devstat_t) ); - - irq_ret = s390_start_IO( irq, - &sense_ccw, - 0x00E2C9C4, // == SID - 0, // n/a - DOIO_WAIT_FOR_INTERRUPT - | DOIO_TIMEOUT ); - - if ( irq_ret == -ETIMEDOUT ) - { - halt_IO( irq, - 0x80E2C9C4, - DOIO_WAIT_FOR_INTERRUPT); - devstat.flag |= DEVSTAT_NOT_OPER; - - } /* endif */ - - if ( sid->cu_type == 0xFFFF && devstat.flag != DEVSTAT_NOT_OPER ) - { - if ( devstat.flag & DEVSTAT_STATUS_PENDING ) - { -#if CONFIG_DEBUG_IO - printk( "Device %04X on Subchannel %04X " - "reports pending status, retry : %d\n", - ioinfo[irq]->schib.pmcw.dev, - irq, - retry); -#endif - } /* endif */ - - if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL ) - { - /* - * if the device doesn't support the SenseID - * command further retries wouldn't help ... - */ - if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT ) - { - retry = 0; - } -#if CONFIG_DEBUG_IO - else - { - printk( "Device %04X," - " UC/SenseID," - " retry %d, cnt %02d," - " sns :" - " %02X%02X%02X%02X %02X%02X%02X%02X ...\n", - ioinfo[irq]->schib.pmcw.dev, - retry, - devstat.scnt, - devstat.ii.sense.data[0], - devstat.ii.sense.data[1], - devstat.ii.sense.data[2], - devstat.ii.sense.data[3], - devstat.ii.sense.data[4], - devstat.ii.sense.data[5], - devstat.ii.sense.data[6], - devstat.ii.sense.data[7]); - - } /* endif */ -#endif - } - else if ( devstat.flag & DEVSTAT_NOT_OPER ) - { - printk( "Device %04X on Subchannel %04X " - "became 'not operational'\n", - ioinfo[irq]->schib.pmcw.dev, - irq); - - retry = 0; - - } /* endif */ - } - else // we got it or the device is not-operational ... - { - retry = 0; - - } /* endif */ - - retry--; - - } while ( retry > 0 ); - - s390irq_spin_unlock( irq); - - /* - * If we installed the irq action handler we have to - * release it too. - */ - if ( inlreq ) - free_irq( irq, &devstat); - - /* - * if running under VM check there ... perhaps we should do - * only if we suffered a command reject, but it doesn't harm - */ - if ( ( sid->cu_type == 0xFFFF ) - && ( MACHINE_IS_VM ) ) - { - VM_virtual_device_info( ioinfo[irq]->schib.pmcw.dev, - sid ); - } /* endif */ - - if ( sid->cu_type == 0xFFFF ) - { - /* - * SenseID CU-type of 0xffff indicates that no device - * information could be retrieved (pre-init value). - * - * If we can't couldn't identify the device type we - * consider the device "not operational". - */ - printk( "Unknown device %04X on subchannel %04X\n", - ioinfo[irq]->schib.pmcw.dev, - irq); - ioinfo[irq]->ui.flags.oper = 0; - - } /* endif */ - - /* - * Issue device info message if unit was operational . - */ - if ( ioinfo[irq]->ui.flags.oper ) - { - if ( sid->dev_type != 0 ) - { - printk( "Device %04X reports: CU Type/Mod = %04X/%02X," - " Dev Type/Mod = %04X/%02X\n", - ioinfo[irq]->schib.pmcw.dev, - sid->cu_type, - sid->cu_model, - sid->dev_type, - sid->dev_model); - } - else - { - printk( "Device %04X reports:" - " Dev Type/Mod = %04X/%02X\n", - ioinfo[irq]->schib.pmcw.dev, - sid->cu_type, - sid->cu_model); - - } /* endif */ - - } /* endif */ - - if ( ioinfo[irq]->ui.flags.oper ) - irq_ret = 0; - else - irq_ret = -ENODEV; - - } /* endif */ - - return( irq_ret ); -} - -static int __inline__ s390_SetMultiPath( int irq ) -{ - int cc; - - cc = stsch( irq, &ioinfo[irq]->schib ); - - if ( !cc ) - { - ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */ - - cc = msch( irq, &ioinfo[irq]->schib ); - - } /* endif */ - - return( cc); -} - -/* - * Device Path Verification - * - * Path verification is accomplished by checking which paths (CHPIDs) are - * available. Further, a path group ID is set, if possible in multipath - * mode, otherwise in single path mode. - * - */ -int s390_DevicePathVerification( int irq ) -{ -#if 0 - int ccode; - __u8 pathmask; - - int ret = 0; - - if ( ioinfo[irq]->ui.flags.pgid_supp == 0 ) - { - ret = -EOPNOTSUPP; - - } /* endif */ - - ccode = stsch( irq, &(ioinfo[irq]->schib) ); - - if ( ccode ) - { - ret = -ENODEV; - } - else - { - int i; - pgid_t pgid; - - int first = 1; - __u8 dev_path = ioinfo[irq]->schib.pmcw.pam - & ioinfo[irq]->schib.pmcw.pom; - - /* - * let's build a path group ID if we don't have one yet - */ - if ( ioinfo[irq]->ui.flags.pgid == 0) - { - struct _lowcore *lowcore = &get_cpu_lowcore(cpu); - - ioinfo->pgid.cpu_addr = lowcore->cpu_data.cpu_addr; - ioinfo->pgid.cpu_id = lowcore->cpu_data.cpu_id.ident; - ioinfo->pgid.cpu_model = lowcore->cpu_data.cpu_id.machine; - ioinfo->pgid.tod_high = *(__u32 *)&irq_IPL_TOD; - - ioinfo[irq]->ui.flags.pgid = 1; - - } /* endif */ - - memcpy( &pgid, ioinfo[irq]->pgid, sizeof(pgid_t)); - - for ( i = 0; i < 8 && !ret ; i++) - { - pathmask = 0x80 >> i; - - if ( dev_path & pathmask ) - { - ret = s390_SetPGID( irq, pathmask, &pgid ); - - /* - * For the *first* path we are prepared - * for recovery - * - * - If we fail setting the PGID we assume its - * using a different PGID already (VM) we - * try to sense. - */ - if ( ret == -EOPNOTSUPP && first ) - { - *(int *)&pgid = 0; - - ret = s390_SensePGID( irq, pathmask, &pgid); - first = 0; - - if ( !ret ) - { - /* - * Check whether we retrieved - * a reasonable PGID ... - */ - if ( !ret && (*(int *)&pgid == 0) ) - { - ret = -EOPNOTSUPP; - } - else - { - ret = s390_SetPGID( irq, pathmask, &pgid ); - - } /* endif */ - - } /* endif */ - - if ( ret ) - { - ioinfo[irq]->ui.flags.pgid_supp = 0; - - printk( "PathVerification(%04X) " - "- Device %04X doesn't " - " support path grouping", - irq, - ioinfo[irq]->schib.pmcw.dev); - - } /* endif */ - } - else if ( ret ) - { - ioinfo[irq]->ui.flags.pgid_supp = 0; - - } /* endif */ - - } /* endif */ - - } /* endfor */ - - } /* endif */ - - return ret; -#else - return 0; -#endif -} - -/* - * s390_SetPGID - * - * Set Path Group ID - * - */ -int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid ) -{ - ccw1_t spid_ccw; /* ccw area for SPID command */ - devstat_t devstat; /* required by request_irq() */ - - int irq_ret = 0; /* return code */ - int retry = 5; /* retry count */ - int inlreq = 0; /* inline request_irq() */ - int mpath = 1; /* try multi-path first */ - - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); - - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - - } /* endif */ - - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( !ioinfo[irq]->ui.flags.ready ) - { - /* - * Perform SENSE ID command processing. We have to request device - * ownership and provide a dummy I/O handler. We issue sync. I/O - * requests and evaluate the devstat area on return therefore - * we don't need a real I/O handler in place. - */ - irq_ret = request_irq( irq, init_IRQ_handler, 0, "SPID", &devstat); - - if ( irq_ret == 0 ) - inlreq = 1; - - } /* endif */ - - if ( irq_ret == 0 ) - { - s390irq_spin_lock( irq); - - spid_ccw.cmd_code = CCW_CMD_SET_PGID; - spid_ccw.cda = (__u32)virt_to_phys( pgid ); - spid_ccw.count = sizeof( pgid_t); - spid_ccw.flags = CCW_FLAG_SLI; - - - /* - * We now issue a SenseID request. In case of BUSY - * or STATUS PENDING conditions we retry 5 times. - */ - do - { - memset( &devstat, '\0', sizeof( devstat_t) ); - - irq_ret = s390_start_IO( irq, - &spid_ccw, - 0xE2D7C9C4, // == SPID - lpm, // n/a - DOIO_WAIT_FOR_INTERRUPT - | DOIO_VALID_LPM ); - - if ( !irq_ret ) - { - if ( devstat.flag & DEVSTAT_STATUS_PENDING ) - { -#if CONFIG_DEBUG_IO - printk( "SPID - Device %04X " - "on Subchannel %04X " - "reports pending status, " - "retry : %d\n", - ioinfo[irq]->schib.pmcw.dev, - irq, - retry); -#endif - } /* endif */ - - if ( devstat.flag == ( DEVSTAT_START_FUNCTION - | DEVSTAT_FINAL_STATUS ) ) - { - retry = 0; // successfully set ... - } - else if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL ) - { - /* - * If the device doesn't support the - * Sense Path Group ID command - * further retries wouldn't help ... - */ - if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT ) - { - if ( mpath ) - { - pgid->inf.fc = SPID_FUNC_ESTABLISH; - mpath = 0; - retry--; - } - else - { - irq_ret = -EOPNOTSUPP; - retry = 0; - - } /* endif */ - } -#if CONFIG_DEBUG_IO - else - { - printk( "SPID - device %04X," - " unit check," - " retry %d, cnt %02d," - " sns :" - " %02X%02X%02X%02X %02X%02X%02X%02X ...\n", - ioinfo[irq]->schib.pmcw.dev, - retry, - devstat.scnt, - devstat.ii.sense.data[0], - devstat.ii.sense.data[1], - devstat.ii.sense.data[2], - devstat.ii.sense.data[3], - devstat.ii.sense.data[4], - devstat.ii.sense.data[5], - devstat.ii.sense.data[6], - devstat.ii.sense.data[7]); - - } /* endif */ -#endif - } - else if ( devstat.flag & DEVSTAT_NOT_OPER ) - { - printk( "SPID - Device %04X " - "on Subchannel %04X " - "became 'not operational'\n", - ioinfo[irq]->schib.pmcw.dev, - irq); - - retry = 0; - - } /* endif */ - } - else if ( irq_ret != -ENODEV ) - { - retry--; - } - else - { - retry = 0; - - } /* endif */ - - } while ( retry > 0 ); - - s390irq_spin_unlock( irq); - - /* - * If we installed the irq action handler we have to - * release it too. - */ - if ( inlreq ) - free_irq( irq, &devstat); - - } /* endif */ - - return( irq_ret ); -} - - -/* - * s390_SensePGID - * - * Sense Path Group ID - * - */ -int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid ) -{ - ccw1_t snid_ccw; /* ccw area for SNID command */ - devstat_t devstat; /* required by request_irq() */ - - int irq_ret = 0; /* return code */ - int retry = 5; /* retry count */ - int inlreq = 0; /* inline request_irq() */ - - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); - - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - - } /* endif */ - - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( !ioinfo[irq]->ui.flags.ready ) - { - /* - * Perform SENSE ID command processing. We have to request device - * ownership and provide a dummy I/O handler. We issue sync. I/O - * requests and evaluate the devstat area on return therefore - * we don't need a real I/O handler in place. - */ - irq_ret = request_irq( irq, init_IRQ_handler, 0, "SNID", &devstat); - - if ( irq_ret == 0 ) - inlreq = 1; - - } /* endif */ - - if ( irq_ret == 0 ) - { - s390irq_spin_lock( irq); - - snid_ccw.cmd_code = CCW_CMD_SENSE_PGID; - snid_ccw.cda = (__u32)virt_to_phys( pgid ); - snid_ccw.count = sizeof( pgid_t); - snid_ccw.flags = CCW_FLAG_SLI; - - /* - * We now issue a SenseID request. In case of BUSY - * or STATUS PENDING conditions we retry 5 times. - */ - do - { - memset( &devstat, '\0', sizeof( devstat_t) ); - - irq_ret = s390_start_IO( irq, - &snid_ccw, - 0xE2D5C9C4, // == SNID - lpm, // n/a - DOIO_WAIT_FOR_INTERRUPT - | DOIO_VALID_LPM ); - - if ( !irq_ret ) - { - if ( devstat.flag & DEVSTAT_STATUS_PENDING ) - { -#if CONFIG_DEBUG_IO - printk( "SNID - Device %04X " - "on Subchannel %04X " - "reports pending status, " - "retry : %d\n", - ioinfo[irq]->schib.pmcw.dev, - irq, - retry); -#endif - } /* endif */ - - if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL ) - { - /* - * If the device doesn't support the - * Sense Path Group ID command - * further retries wouldn't help ... - */ - if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT ) - { - retry = 0; - irq_ret = -EOPNOTSUPP; - } -#if CONFIG_DEBUG_IO - else - { - printk( "SNID - device %04X," - " unit check," - " retry %d, cnt %02d," - " sns :" - " %02X%02X%02X%02X %02X%02X%02X%02X ...\n", - ioinfo[irq]->schib.pmcw.dev, - retry, - devstat.scnt, - devstat.ii.sense.data[0], - devstat.ii.sense.data[1], - devstat.ii.sense.data[2], - devstat.ii.sense.data[3], - devstat.ii.sense.data[4], - devstat.ii.sense.data[5], - devstat.ii.sense.data[6], - devstat.ii.sense.data[7]); - - } /* endif */ -#endif - } - else if ( devstat.flag & DEVSTAT_NOT_OPER ) - { - printk( "SNID - Device %04X " - "on Subchannel %04X " - "became 'not operational'\n", - ioinfo[irq]->schib.pmcw.dev, - irq); - - retry = 0; - - } /* endif */ - } - else if ( irq_ret != -ENODEV ) - { - retry--; - } - else - { - retry = 0; - - } /* endif */ - - } while ( retry > 0 ); - - s390irq_spin_unlock( irq); - - /* - * If we installed the irq action handler we have to - * release it too. - */ - if ( inlreq ) - free_irq( irq, &devstat); - - } /* endif */ - - return( irq_ret ); -} - - -void do_crw_pending( void ) -{ - return; -} - - -/* added by Holger Smolinski for reipl support in reipl.S */ -void -reipl ( int sch ) -{ - int i; - - for ( i = 0; i < highest_subchannel; i ++ ) { - free_irq ( i, (void*)REIPL_DEVID_MAGIC ); - } - do_reipl( 0x10000 | sch ); -} - diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/s390mach.c linux/arch/s390/kernel/s390mach.c --- v2.4.1/linux/arch/s390/kernel/s390mach.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/kernel/s390mach.c Wed Dec 31 16:00:00 1969 @@ -1,157 +0,0 @@ -/* - * arch/s390/kernel/s390mach.c - * S/390 machine check handler, - * currently only channel-reports are supported - * - * S390 version - * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Ingo Adlung (adlung@de.ibm.com) - */ - -#include - -#include -#include -#include -#include -#include -#include - -#define S390_MACHCHK_DEBUG - -static mchchk_queue_element_t *mchchk_queue_head = NULL; -static mchchk_queue_element_t *mchchk_queue_tail = NULL; -static mchchk_queue_element_t *mchchk_queue_free = NULL; -static spinlock_t mchchk_queue_lock; -static struct semaphore s_sem[2]; - -// -// initialize machine check handling -// -void s390_init_machine_check( void ) -{ - init_MUTEX_LOCKED( &s_sem[0] ); - init_MUTEX_LOCKED( &s_sem[1] ); - -#if 0 - // - // fix me ! initialize a machine check queue with 100 elements - // -#ifdef S390_MACHCHK_DEBUG - printk( "init_mach : starting kernel thread\n"); -#endif - - kernel_thread( s390_machine_check_handler, s_sem, 0); - - // - // wait for the machine check handler to be ready - // -#ifdef S390_MACHCHK_DEBUG - printk( "init_mach : waiting for kernel thread\n"); -#endif - - down( &sem[0]); - -#ifdef S390_MACHCHK_DEBUG - printk( "init_mach : kernel thread ready\n"); -#endif - - // - // fix me ! we have to initialize CR14 to allow for CRW pending - // conditions - - // - // fix me ! enable machine checks in the PSW - // -#endif - return; -} - -// -// machine check pre-processor -// -void __init s390_do_machine_check( void ) -{ - // fix me ! we have to check for machine check and - // post the handler eventually - - return; -} - -// -// machine check handler -// -static void __init s390_machine_check_handler( struct semaphore *sem ) -{ -#ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : kernel thread up\n"); -#endif - - up( &sem[0] ); - -#ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : kernel thread ready\n"); -#endif - - do { - -#ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : waiting for wakeup\n"); -#endif - - down_interruptible( &sem[1] ); -#ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : wakeup\n"); -#endif - - break; // fix me ! unconditional surrender ... - - // fix me ! check for machine checks and - // call do_crw_pending() eventually - - } while (1); - - return; -} - -mchchk_queue_element_t *s390_get_mchchk( void ) -{ - unsigned long flags; - mchchk_queue_element_t *qe; - - spin_lock_irqsave( &mchchk_queue_lock, flags ); - - // fix me ! dequeue first element if available - qe = NULL; - - spin_unlock_irqrestore( &mchchk_queue_lock, flags ); - - return qe; -} - -void s390_free_mchchk( mchchk_queue_element_t *mchchk ) -{ - unsigned long flags; - - if ( mchchk != NULL) - { - spin_lock_irqsave( &mchchk_queue_lock, flags ); - - mchchk->next = mchchk_queue_free; - - if ( mchchk_queue_free != NULL ) - { - mchchk_queue_free->prev = mchchk; - - } /* endif */ - - mchchk->prev = NULL; - mchchk_queue_free = mchchk; - - spin_unlock_irqrestore( &mchchk_queue_lock, flags ); - - } /* endif */ - - return; -} - diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/semaphore.c linux/arch/s390/kernel/semaphore.c --- v2.4.1/linux/arch/s390/kernel/semaphore.c Sat Nov 11 19:02:40 2000 +++ linux/arch/s390/kernel/semaphore.c Tue Feb 13 14:13:44 2001 @@ -2,7 +2,7 @@ * linux/arch/S390/kernel/semaphore.c * * S390 version - * Copyright (C) 1998 IBM Corporation + * Copyright (C) 1998-2000 IBM Corporation * Author(s): Martin Schwidefsky * * Derived from "linux/arch/i386/kernel/semaphore.c diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c --- v2.4.1/linux/arch/s390/kernel/setup.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/kernel/setup.c Tue Feb 13 14:13:44 2001 @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -45,6 +45,7 @@ __u16 boot_cpu_addr; int cpus_initialized = 0; unsigned long cpu_initialized = 0; +volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ /* * Setup options @@ -80,6 +81,7 @@ void __init cpu_init (void) { int nr = smp_processor_id(); + int addr = hard_smp_processor_id(); if (test_and_set_bit(nr,&cpu_initialized)) { printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr); @@ -91,7 +93,7 @@ * Store processor id in lowcore (used e.g. in timer_interrupt) */ asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id)); - S390_lowcore.cpu_data.cpu_addr = hard_smp_processor_id(); + S390_lowcore.cpu_data.cpu_addr = addr; S390_lowcore.cpu_data.cpu_nr = nr; /* @@ -158,33 +160,18 @@ { if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) cpcmd(vmhalt_cmd, NULL, 0); - disabled_wait(0); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); } void machine_power_off(void) { if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) cpcmd(vmpoff_cmd, NULL, 0); - disabled_wait(0); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); } #endif /* - * Waits for 'delay' microseconds using the tod clock - */ -void tod_wait(unsigned long delay) -{ - uint64_t start_cc, end_cc; - - if (delay == 0) - return; - asm volatile ("STCK %0" : "=m" (start_cc)); - do { - asm volatile ("STCK %0" : "=m" (end_cc)); - } while (((end_cc - start_cc)/4096) < delay); -} - -/* * Setup function called from init/main.c just after the banner * was printed. */ @@ -192,12 +179,11 @@ { unsigned long bootmap_size; unsigned long memory_start, memory_end; - char c = ' ', *to = command_line, *from = COMMAND_LINE; + char c = ' ', cn, *to = command_line, *from = COMMAND_LINE; struct resource *res; unsigned long start_pfn, end_pfn; static unsigned int smptrap=0; unsigned long delay = 0; - int len = 0; if (smptrap) return; @@ -210,6 +196,7 @@ */ cpu_init(); boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr; + __cpu_logical_map[0] = boot_cpu_addr; /* * print what head.S has found out about the machine @@ -227,10 +214,15 @@ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif - /* nasty stuff with PARMAREAs. we use head.S or parameterline - if (!MOUNT_ROOT_RDONLY) - root_mountflags &= ~MS_RDONLY; - */ + memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ + memory_end = MEMORY_SIZE; + /* + * We need some free virtual space to be able to do vmalloc. + * On a machine with 2GB memory we make sure that we have at + * least 128 MB free space for vmalloc. + */ + if (memory_end > 1920*1024*1024) + memory_end = 1920*1024*1024; memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ memory_end = MEMORY_SIZE; /* detected in head.s */ init_mm.start_code = PAGE_OFFSET; @@ -252,7 +244,6 @@ * "mem=XXX[kKmM]" sets memsize */ if (c == ' ' && strncmp(from, "mem=", 4) == 0) { - if (to != command_line) to--; memory_end = simple_strtoul(from+4, &from, 0); if ( *from == 'K' || *from == 'k' ) { memory_end = memory_end << 10; @@ -275,16 +266,22 @@ delay = delay*60*1000000; from++; } - /* now wait for the requestion amount of time */ - tod_wait(delay); + /* now wait for the requestedn amount of time */ + udelay(delay); } - c = *(from++); - if (!c) + cn = *(from++); + if (!cn) break; - if (COMMAND_LINE_SIZE <= ++len) + if (cn == '\n') + cn = ' '; /* replace newlines with space */ + if (cn == ' ' && c == ' ') + continue; /* remove additional spaces */ + c = cn; + if (to - command_line >= COMMAND_LINE_SIZE) break; *(to++) = c; } + if (c == ' ' && to > command_line) to--; *to = '\0'; *cmdline_p = command_line; @@ -317,7 +314,7 @@ paging_init(); #ifdef CONFIG_BLK_DEV_INITRD if (INITRD_START) { - if (INITRD_START + INITRD_SIZE < memory_end) { + if (INITRD_START + INITRD_SIZE <= memory_end) { reserve_bootmem(INITRD_START, INITRD_SIZE); initrd_start = INITRD_START; initrd_end = initrd_start + INITRD_SIZE; @@ -368,8 +365,8 @@ p += sprintf(p,"vendor_id : IBM/S390\n" "# processors : %i\n" "bogomips per cpu: %lu.%02lu\n", - smp_num_cpus, loops_per_sec/500000, - (loops_per_sec/5000)%100); + smp_num_cpus, loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ))%100); for (i = 0; i < smp_num_cpus; i++) { cpuinfo = &safe_get_cpu_lowcore(i).cpu_data; p += sprintf(p,"processor %i: " diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c --- v2.4.1/linux/arch/s390/kernel/signal.c Sat Feb 3 19:51:24 2001 +++ linux/arch/s390/kernel/signal.c Tue Feb 13 14:13:44 2001 @@ -2,7 +2,7 @@ * arch/s390/kernel/signal.c * * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) * * Based on Intel version @@ -37,7 +37,7 @@ #define SIGFRAME_COMMON \ __u8 callee_used_stack[__SIGNAL_FRAMESIZE]; \ struct sigcontext sc; \ -sigregs sregs; \ +_sigregs sregs; \ __u8 retcode[S390_SYSCALL_SIZE]; typedef struct @@ -54,6 +54,41 @@ asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -71,7 +106,7 @@ regs->gprs[2] = -EINTR; while (1) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule(); if (do_signal(regs, &saveset)) return -EINTR; @@ -99,7 +134,7 @@ regs->gprs[2] = -EINTR; while (1) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule(); if (do_signal(regs, &saveset)) return -EINTR; @@ -139,16 +174,15 @@ } asmlinkage int -sys_sigaltstack(const stack_t *uss, stack_t *uoss) +sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *) &uss; return do_sigaltstack(uss, uoss, regs->gprs[15]); } -static int save_sigregs(struct pt_regs *regs,sigregs *sregs) +static int save_sigregs(struct pt_regs *regs,_sigregs *sregs) { int err; s390_fp_regs fpregs; @@ -163,7 +197,7 @@ } -static int restore_sigregs(struct pt_regs *regs,sigregs *sregs) +static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs) { int err; s390_fp_regs fpregs; @@ -185,13 +219,13 @@ static int restore_sigcontext(struct sigcontext *sc, pt_regs *regs, - sigregs *sregs,sigset_t *set) + _sigregs *sregs,sigset_t *set) { unsigned int err; err=restore_sigregs(regs,sregs); if(!err) - err=__copy_from_user(&set->sig,&sc->oldmask,SIGMASK_COPY_SIZE); + err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE); return(err); } @@ -227,15 +261,12 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) { rt_sigframe *frame = (rt_sigframe *)regs->gprs[15]; - stack_t st; if (sigreturn_common(regs,sizeof(rt_sigframe))) goto badframe; - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) - goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs->gprs[15]); + do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]); return regs->gprs[2]; badframe: @@ -290,7 +321,7 @@ err=__put_user(&frame->sregs,&frame->sc.sregs); if(!err) - err=__copy_to_user(&frame->sc.oldmask,&set->sig,SIGMASK_COPY_SIZE); + err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE); if(!err) { regs->gprs[2]=(current->exec_domain @@ -316,14 +347,17 @@ static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { + sigframe *frame; - if(!setup_frame_common(sig,ka,set,regs,sizeof(sigframe), - (S390_SYSCALL_OPCODE|__NR_sigreturn))) + if((frame=setup_frame_common(sig,ka,set,regs,sizeof(sigframe), + (S390_SYSCALL_OPCODE|__NR_sigreturn)))==0) goto give_sigsegv; #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->eip, frame->pretcode); #endif + /* Martin wants this for pthreads */ + regs->gprs[3] = (addr_t)&frame->sc; return; give_sigsegv: @@ -343,7 +377,7 @@ (S390_SYSCALL_OPCODE|__NR_rt_sigreturn)))==0) goto give_sigsegv; - err = __copy_to_user(&frame->info, info, sizeof(*info)); + err = copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); @@ -352,8 +386,9 @@ err |= __put_user(sas_ss_flags(orig_sp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - regs->gprs[3] = (u32)&frame->info; - regs->gprs[4] = (u32)&frame->uc; + err |= __put_user(&frame->sc,&frame->uc.sc); + regs->gprs[3] = (addr_t)&frame->info; + regs->gprs[4] = (addr_t)&frame->uc; if (err) goto give_sigsegv; @@ -452,10 +487,10 @@ if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; - current->state = TASK_STOPPED; + set_current_state(TASK_STOPPED); notify_parent(current, SIGCHLD); schedule(); @@ -511,7 +546,7 @@ /* FALLTHRU */ case SIGSTOP: - current->state = TASK_STOPPED; + set_current_state(TASK_STOPPED); current->exit_code = signr; if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); @@ -540,7 +575,7 @@ } /* Did we come from a system call? */ - if ( regs->trap == 0x20 /* System Call! */ ) { + if ( regs->trap == __LC_SVC_OLD_PSW /* System Call! */ ) { /* Restart the system call - no handlers present */ if (regs->gprs[2] == -ERESTARTNOHAND || regs->gprs[2] == -ERESTARTSYS || diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c --- v2.4.1/linux/arch/s390/kernel/smp.c Tue Sep 5 13:50:01 2000 +++ linux/arch/s390/kernel/smp.c Tue Feb 13 14:13:44 2001 @@ -32,16 +32,15 @@ #include #include #include +#include #include "cpcmd.h" /* prototypes */ -extern void update_one_process( struct task_struct *p, - unsigned long ticks, unsigned long user, - unsigned long system, int cpu); extern int cpu_idle(void * unused); extern __u16 boot_cpu_addr; +extern volatile int __cpu_logical_map[]; /* * An array with a pointer the lowcore of every CPU. @@ -52,10 +51,8 @@ unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_old_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; -volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ cycles_t cacheflush_time=0; int smp_threads_ready=0; /* Set when the idlers are all forked. */ -unsigned long ipi_count=0; /* Number of IPIs delivered. */ static atomic_t smp_commenced = ATOMIC_INIT(0); spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; @@ -104,7 +101,7 @@ void machine_restart(char * __unused) { if (smp_processor_id() != 0) { - smp_ext_call_async(0, ec_restart); + smp_ext_bitcall(0, ec_restart); for (;;); } else do_machine_restart(); @@ -115,13 +112,13 @@ smp_send_stop(); if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) cpcmd(vmhalt_cmd, NULL, 0); - disabled_wait(0); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); } void machine_halt(void) { if (smp_processor_id() != 0) { - smp_ext_call_async(0, ec_halt); + smp_ext_bitcall(0, ec_halt); for (;;); } else do_machine_halt(); @@ -132,13 +129,13 @@ smp_send_stop(); if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) cpcmd(vmpoff_cmd, NULL, 0); - disabled_wait(0); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); } void machine_power_off(void) { if (smp_processor_id() != 0) { - smp_ext_call_async(0, ec_power_off); + smp_ext_bitcall(0, ec_power_off); for (;;); } else do_machine_power_off(); @@ -149,7 +146,7 @@ * cpus are handled. */ -void do_ext_call_interrupt(__u16 source_cpu_addr) +void do_ext_call_interrupt(struct pt_regs *regs, __u16 code) { ec_ext_call *ec, *next; int bits; @@ -172,6 +169,8 @@ do_machine_halt(); if (test_bit(ec_power_off, &bits)) do_machine_power_off(); + if (test_bit(ec_ptlb, &bits)) + local_flush_tlb(); /* * Handle external call commands with a parameter area @@ -184,7 +183,7 @@ return; /* no command signals */ /* Make a fifo out of the lifo */ - next = ec; + next = ec->next; ec->next = NULL; while (next != NULL) { ec_ext_call *tmp = next->next; @@ -196,61 +195,21 @@ /* Execute every sigp command on the queue */ while (ec != NULL) { switch (ec->cmd) { - case ec_get_ctl: { - ec_creg_parms *pp; - pp = (ec_creg_parms *) ec->parms; - atomic_set(&ec->status,ec_executing); - asm volatile ( - " bras 1,0f\n" - " stctl 0,0,0(%0)\n" - "0: ex %1,0(1)\n" - : : "a" (pp->cregs+pp->start_ctl), - "a" ((pp->start_ctl<<4) + pp->end_ctl) - : "memory", "1" ); - atomic_set(&ec->status,ec_done); - return; - } - case ec_set_ctl: { - ec_creg_parms *pp; - pp = (ec_creg_parms *) ec->parms; + case ec_callback_async: { + void (*func)(void *info); + void *info; + + func = ec->func; + info = ec->info; atomic_set(&ec->status,ec_executing); - asm volatile ( - " bras 1,0f\n" - " lctl 0,0,0(%0)\n" - "0: ex %1,0(1)\n" - : : "a" (pp->cregs+pp->start_ctl), - "a" ((pp->start_ctl<<4) + pp->end_ctl) - : "memory", "1" ); - atomic_set(&ec->status,ec_done); + (func)(info); return; } - case ec_set_ctl_masked: { - ec_creg_mask_parms *pp; - u32 cregs[16]; - int i; - - pp = (ec_creg_mask_parms *) ec->parms; + case ec_callback_sync: atomic_set(&ec->status,ec_executing); - asm volatile ( - " bras 1,0f\n" - " stctl 0,0,0(%0)\n" - "0: ex %1,0(1)\n" - : : "a" (cregs+pp->start_ctl), - "a" ((pp->start_ctl<<4) + pp->end_ctl) - : "memory", "1" ); - for (i = pp->start_ctl; i <= pp->end_ctl; i++) - cregs[i] = (cregs[i] & pp->andvals[i]) - | pp->orvals[i]; - asm volatile ( - " bras 1,0f\n" - " lctl 0,0,0(%0)\n" - "0: ex %1,0(1)\n" - : : "a" (cregs+pp->start_ctl), - "a" ((pp->start_ctl<<4) + pp->end_ctl) - : "memory", "1" ); + (ec->func)(ec->info); atomic_set(&ec->status,ec_done); return; - } default: } ec = ec->next; @@ -258,17 +217,19 @@ } /* - * Send an external call sigp to another cpu and wait for its completion. + * Send a callback sigp to another cpu. */ -sigp_ccode smp_ext_call_sync(int cpu, ec_cmd_sig cmd, void *parms) +sigp_ccode +smp_ext_call(int cpu, void (*func)(void *info), void *info, int wait) { struct _lowcore *lowcore = &get_cpu_lowcore(cpu); sigp_ccode ccode; ec_ext_call ec; - ec.cmd = cmd; + ec.cmd = wait ? ec_callback_sync : ec_callback_async; atomic_set(&ec.status, ec_pending); - ec.parms = parms; + ec.func = func; + ec.info = info; do { ec.next = (ec_ext_call*) atomic_read(&lowcore->ext_call_queue); } while (atomic_compare_and_swap((int) ec.next, (int)(&ec), @@ -288,34 +249,15 @@ if (ccode != sigp_not_operational) /* wait for completion, FIXME: possible seed of a deadlock */ - while (atomic_read(&ec.status) != ec_done); - - return ccode; -} - -/* - * Send an external call sigp to another cpu and return without waiting - * for its completion. Currently we do not support parameters with - * asynchronous sigps. - */ -sigp_ccode smp_ext_call_async(int cpu, ec_bit_sig sig) -{ - struct _lowcore *lowcore = &get_cpu_lowcore(cpu); - sigp_ccode ccode; + while (atomic_read(&ec.status) != (wait?ec_done:ec_executing)); - /* - * Set signaling bit in lowcore of target cpu and kick it - */ - atomic_set_mask(1<ext_call_fast); - ccode = signal_processor(cpu, sigp_external_call); return ccode; } /* - * Send an external call sigp to every other cpu in the system and - * wait for the completion of the sigps. + * Send a callback sigp to every other cpu in the system. */ -void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms) +void smp_ext_call_others(void (*func)(void *info), void *info, int wait) { struct _lowcore *lowcore; ec_ext_call ec[NR_CPUS]; @@ -326,9 +268,10 @@ if (smp_processor_id() == i) continue; lowcore = &get_cpu_lowcore(i); - ec[i].cmd = cmd; - atomic_set(&ec[i].status, ec_pending); - ec[i].parms = parms; + ec[i].cmd = wait ? ec_callback_sync : ec_callback_async; + atomic_set(&ec[i].status, ec_pending); + ec[i].func = func; + ec[i].info = info; do { ec[i].next = (ec_ext_call *) atomic_read(&lowcore->ext_call_queue); @@ -341,16 +284,33 @@ for (i = 0; i < smp_num_cpus; i++) { if (smp_processor_id() == i) continue; - while (atomic_read(&ec[i].status) != ec_done); + while (atomic_read(&ec[i].status) != + (wait ? ec_done:ec_executing)); } } /* + * Send an external call sigp to another cpu and return without waiting + * for its completion. + */ +sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig) +{ + struct _lowcore *lowcore = &get_cpu_lowcore(cpu); + sigp_ccode ccode; + + /* + * Set signaling bit in lowcore of target cpu and kick it + */ + atomic_set_mask(1<ext_call_fast); + ccode = signal_processor(cpu, sigp_external_call); + return ccode; +} + +/* * Send an external call sigp to every other cpu in the system and - * return without waiting for the completion of the sigps. Currently - * we do not support parameters with asynchronous sigps. + * return without waiting for its completion. */ -void smp_ext_call_async_others(ec_bit_sig sig) +void smp_ext_bitcall_others(ec_bit_sig sig) { struct _lowcore *lowcore; sigp_ccode ccode; @@ -420,7 +380,46 @@ void smp_send_stop(void) { - smp_signal_others(sigp_stop, 0, 1, NULL); + int i; + u32 dummy; + unsigned long low_core_addr; + + /* write magic number to zero page (absolute 0) */ + + get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC; + + /* stop all processors */ + + smp_signal_others(sigp_stop, 0, TRUE, NULL); + + /* store status of all processors in their lowcores (real 0) */ + + for (i = 0; i < smp_num_cpus; i++) { + if (smp_processor_id() != i) { + int ccode; + low_core_addr = (unsigned long)&get_cpu_lowcore(i); + do { + ccode = signal_processor_ps( + &dummy, + low_core_addr, + i, + sigp_store_status_at_address); + } while(ccode == sigp_busy); + } + } +} + +/* + * this function sends a 'purge tlb' signal to another CPU. + */ +void smp_ptlb_callback(void *info) +{ + local_flush_tlb(); +} + +void smp_ptlb_all(void) +{ + smp_ext_call_others(smp_ptlb_callback, NULL, 1); } /* @@ -431,7 +430,44 @@ void smp_send_reschedule(int cpu) { - smp_ext_call_async(cpu, ec_schedule); + smp_ext_bitcall(cpu, ec_schedule); +} + +/* + * parameter area for the set/clear control bit callbacks + */ +typedef struct +{ + __u16 start_ctl; + __u16 end_ctl; + __u32 orvals[16]; + __u32 andvals[16]; +} ec_creg_mask_parms; + +/* + * callback for setting/clearing control bits + */ +void smp_ctl_bit_callback(void *info) { + ec_creg_mask_parms *pp; + u32 cregs[16]; + int i; + + pp = (ec_creg_mask_parms *) info; + asm volatile (" bras 1,0f\n" + " stctl 0,0,0(%0)\n" + "0: ex %1,0(1)\n" + : : "a" (cregs+pp->start_ctl), + "a" ((pp->start_ctl<<4) + pp->end_ctl) + : "memory", "1" ); + for (i = pp->start_ctl; i <= pp->end_ctl; i++) + cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i]; + asm volatile (" bras 1,0f\n" + " lctl 0,0,0(%0)\n" + "0: ex %1,0(1)\n" + : : "a" (cregs+pp->start_ctl), + "a" ((pp->start_ctl<<4) + pp->end_ctl) + : "memory", "1" ); + return; } /* @@ -445,7 +481,7 @@ parms.end_ctl = cr; parms.orvals[cr] = 1 << bit; parms.andvals[cr] = 0xFFFFFFFF; - smp_ext_call_sync_others(ec_set_ctl_masked,&parms); + smp_ext_call_others(smp_ctl_bit_callback, &parms, 1); } __ctl_set_bit(cr, bit); } @@ -461,11 +497,35 @@ parms.end_ctl = cr; parms.orvals[cr] = 0x00000000; parms.andvals[cr] = ~(1 << bit); - smp_ext_call_sync_others(ec_set_ctl_masked,&parms); + smp_ext_call_others(smp_ctl_bit_callback, &parms, 1); } __ctl_clear_bit(cr, bit); } +/* + * Call a function on all other processors + */ + +int +smp_call_function(void (*func)(void *info), void *info, int retry, int wait) +/* + * [SUMMARY] Run a function on all other CPUs. + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * currently unused. + * If true, wait (atomically) until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. Does not return until + * remote CPUs are nearly ready to execute <> or are or have executed. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler, you may call it from a bottom half handler. + */ +{ + if (atomic_read(&smp_commenced) != 0) + smp_ext_call_others(func, info, 1); + (func)(info); + return 0; +} /* * Lets check how many CPUs we have. @@ -475,7 +535,6 @@ { int curr_cpu; - __cpu_logical_map[0] = boot_cpu_addr; current->processor = 0; smp_num_cpus = 1; for (curr_cpu = 0; @@ -527,7 +586,7 @@ struct pt_regs regs; /* don't care about the psw and regs settings since we'll never reschedule the forked task. */ - memset(®s,sizeof(pt_regs),0); + memset(®s,0,sizeof(pt_regs)); return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } @@ -594,7 +653,10 @@ struct _lowcore *curr_lowcore; sigp_ccode ccode; int i; - + + /* request the 0x1202 external interrupt */ + if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0) + panic("Couldn't request external interrupt 0x1202"); smp_count_cpus(); memset(lowcore_ptr,0,sizeof(lowcore_ptr)); @@ -705,24 +767,7 @@ */ irq_enter(cpu, 0); - update_one_process(p, 1, user, system, cpu); - if (p->pid) { - p->counter -= 1; - if (p->counter <= 0) { - p->counter = 0; - p->need_resched = 1; - } - if (p->nice > 0) { - kstat.cpu_nice += user; - kstat.per_cpu_nice[cpu] += user; - } else { - kstat.cpu_user += user; - kstat.per_cpu_user[cpu] += user; - } - kstat.cpu_system += system; - kstat.per_cpu_system[cpu] += system; - - } + update_process_times(user); irq_exit(cpu, 0); } } diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/sys_s390.c linux/arch/s390/kernel/sys_s390.c --- v2.4.1/linux/arch/s390/kernel/sys_s390.c Wed Jul 5 11:31:01 2000 +++ linux/arch/s390/kernel/sys_s390.c Tue Feb 13 14:13:44 2001 @@ -71,18 +71,10 @@ return error; } -/* FIXME: 6 parameters is one too much ... */ -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); -} - /* * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux/i386 didn't use to be able to handle more than - * 4 system call parameters, so these system calls used a memory + * calls. Linux for S/390 isn't able to handle more than 5 + * system call parameters, so these system calls used a memory * block for parameter passing.. */ @@ -95,6 +87,18 @@ unsigned long offset; }; +asmlinkage long sys_mmap2(struct mmap_arg_struct *arg) +{ + struct mmap_arg_struct a; + int error = -EFAULT; + + if (copy_from_user(&a, arg, sizeof(a))) + goto out; + error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); +out: + return error; +} + asmlinkage int old_mmap(struct mmap_arg_struct *arg) { struct mmap_arg_struct a; @@ -239,7 +243,7 @@ asmlinkage int sys_pause(void) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule(); return -ERESTARTNOHAND; } diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/time.c linux/arch/s390/kernel/time.c --- v2.4.1/linux/arch/s390/kernel/time.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/kernel/time.c Tue Feb 13 14:13:44 2001 @@ -11,7 +11,6 @@ * Copyright (C) 1991, 1992, 1995 Linus Torvalds */ -#include #include #include #include @@ -27,15 +26,14 @@ #include #include +#include -#include #include +#include #include -extern volatile unsigned long lost_ticks; - /* change this if you have some constant time drift */ #define USECS_PER_JIFFY ((signed long)1000000/HZ) #define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12) @@ -45,6 +43,7 @@ static uint64_t init_timer_cc, last_timer_cc; extern rwlock_t xtime_lock; +extern unsigned long wall_jiffies; void tod_to_timeval(uint64_t todval, struct timeval *xtime) { @@ -94,9 +93,9 @@ */ void do_gettimeofday(struct timeval *tv) { - extern volatile unsigned long lost_ticks; unsigned long flags; unsigned long usec, sec; + unsigned long lost_ticks = jiffies - wall_jiffies; read_lock_irqsave(&xtime_lock, flags); usec = do_gettimeoffset(); @@ -149,7 +148,7 @@ extern __u16 boot_cpu_addr; #endif -void do_timer_interrupt(struct pt_regs *regs,int error_code) +void do_timer_interrupt(struct pt_regs *regs, __u16 error_code) { unsigned long flags; @@ -242,6 +241,9 @@ printk("time_init: TOD clock stopped/non-operational\n"); break; } + /* request the 0x1004 external interrupt */ + if (register_external_interrupt(0x1004, do_timer_interrupt) != 0) + panic("Couldn't request external interrupts 0x1004"); init_100hz_timer(); init_timer_cc = S390_lowcore.jiffy_timer_cc; init_timer_cc -= 0x8126d60e46000000LL - diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c --- v2.4.1/linux/arch/s390/kernel/traps.c Sun Dec 3 17:48:19 2000 +++ linux/arch/s390/kernel/traps.c Tue Feb 13 14:13:44 2001 @@ -42,122 +42,15 @@ typedef void pgm_check_handler_t(struct pt_regs *, long); pgm_check_handler_t *pgm_check_table[128]; -extern pgm_check_handler_t default_trap_handler; -extern pgm_check_handler_t do_page_fault; - -asmlinkage int system_call(void); - -#define DO_ERROR(trapnr, signr, str, name, tsk) \ -asmlinkage void name(struct pt_regs * regs, long error_code) \ -{ \ - tsk->thread.error_code = error_code; \ - tsk->thread.trap_no = trapnr; \ - die_if_no_fixup(str,regs,error_code); \ - force_sig(signr, tsk); \ -} - -/* TODO: define these as 'pgm_check_handler_t xxx;' -asmlinkage void divide_error(void); -asmlinkage void debug(void); -asmlinkage void nmi(void); -asmlinkage void int3(void); -asmlinkage void overflow(void); -asmlinkage void bounds(void); -asmlinkage void invalid_op(void); -asmlinkage void device_not_available(void); -asmlinkage void double_fault(void); -asmlinkage void coprocessor_segment_overrun(void); -asmlinkage void invalid_TSS(void); -asmlinkage void segment_not_present(void); -asmlinkage void stack_segment(void); -asmlinkage void general_protection(void); -asmlinkage void coprocessor_error(void); -asmlinkage void reserved(void); -asmlinkage void alignment_check(void); -asmlinkage void spurious_interrupt_bug(void); -*/ - -int kstack_depth_to_print = 24; - -/* - * These constants are for searching for possible module text - * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is - * a guess of how much space is likely to be vmalloced. - */ -#define VMALLOC_OFFSET (8*1024*1024) -#define MODULE_RANGE (8*1024*1024) - -void show_crashed_task_info(void) -{ - printk("CPU: %d\n",smp_processor_id()); - printk("Process %s (pid: %d, stackpage=%08X)\n", - current->comm, current->pid, 4096+(addr_t)current); - show_regs(current,NULL,NULL); -} -#if 0 -static void show_registers(struct pt_regs *regs) -{ - printk("CPU: %d\nPSW: %08lx %08lx\n", - smp_processor_id(), (unsigned long) regs->psw.mask, - (unsigned long) regs->psw.addr); - printk("GPRS:\n"); - - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[0], regs->gprs[1], - regs->gprs[2], regs->gprs[3]); - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[4], regs->gprs[5], - regs->gprs[6], regs->gprs[7]); - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[8], regs->gprs[9], - regs->gprs[10], regs->gprs[11]); - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[12], regs->gprs[13], - regs->gprs[14], regs->gprs[15]); - printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ", - current->comm, current->pid, 4096+(unsigned long)current); -/* - stack = (unsigned long *) esp; - for(i=0; i < kstack_depth_to_print; i++) { - if (((long) stack & 4095) == 0) - break; - if (i && ((i % 8) == 0)) - printk("\n "); - printk("%08lx ", get_seg_long(ss,stack++)); - } - printk("\nCall Trace: "); - stack = (unsigned long *) esp; - i = 1; - module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); - module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); - module_end = module_start + MODULE_RANGE; - while (((long) stack & 4095) != 0) { - addr = get_seg_long(ss, stack++); */ - /* - * If the address is either in the text segment of the - * kernel, or in the region which contains vmalloc'ed - * memory, it *may* be the address of a calling - * routine; if so, print it so that someone tracing - * down the cause of the crash will be able to figure - * out the call path that was taken. - */ -/* if (((addr >= (unsigned long) &_stext) && - (addr <= (unsigned long) &_etext)) || - ((addr >= module_start) && (addr <= module_end))) { - if (i && ((i % 8) == 0)) - printk("\n "); - printk("[<%08lx>] ", addr); - i++; - } - } - printk("\nCode: "); - for(i=0;i<20;i++) - printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip))); - printk("\n"); -*/ -} +#ifdef CONFIG_SYSCTL +#ifdef CONFIG_PROCESS_DEBUG +int sysctl_userprocess_debug = 1; +#else +int sysctl_userprocess_debug = 0; +#endif #endif +extern pgm_check_handler_t do_page_fault; spinlock_t die_lock; @@ -166,29 +59,65 @@ console_verbose(); spin_lock_irq(&die_lock); printk("%s: %04lx\n", str, err & 0xffff); - show_crashed_task_info(); + show_regs(regs); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } -int check_for_fixup(struct pt_regs * regs) -{ - if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { - unsigned long fixup; - fixup = search_exception_table(regs->psw.addr); - if (fixup) { - regs->psw.addr = fixup; - return 1; +#define DO_ERROR(signr, str, name) \ +asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +{ \ + do_trap(interruption_code, signr, str, regs, NULL); \ +} + +#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ +asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void *)siaddr; \ + do_trap(interruption_code, signr, str, regs, &info); \ +} + +static void inline do_trap(long interruption_code, int signr, char *str, + struct pt_regs *regs, siginfo_t *info) +{ + if (regs->psw.mask & PSW_PROBLEM_STATE) { + struct task_struct *tsk = current; + tsk->thread.trap_no = interruption_code; + if (info) + force_sig_info(signr, info, tsk); + else + force_sig(signr, tsk); +#ifndef CONFIG_SYSCTL +#ifdef CONFIG_PROCESS_DEBUG + printk("User process fault: interruption code 0x%lX\n", + interruption_code); + show_regs(regs); +#endif +#else + if (sysctl_userprocess_debug) { + printk("User process fault: interruption code 0x%lX\n", + interruption_code); + show_regs(regs); } - } - return 0; +#endif + } else { + unsigned long fixup = search_exception_table(regs->psw.addr); + if (fixup) + regs->psw.addr = fixup; + else + die(str, regs, interruption_code); + } } int do_debugger_trap(struct pt_regs *regs,int signal) { if(regs->psw.mask&PSW_PROBLEM_STATE) { - if(current->flags & PF_PTRACED) + if(current->ptrace & PT_PTRACED) force_sig(signal,current); else return 1; @@ -207,50 +136,16 @@ return 0; } -static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) -{ - if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { - unsigned long fixup; - fixup = search_exception_table(regs->psw.addr); - if (fixup) { - regs->psw.addr = fixup; - return; - } - die(str, regs, err); - } -} - -asmlinkage void default_trap_handler(struct pt_regs * regs, long error_code) -{ - current->thread.error_code = error_code; - current->thread.trap_no = error_code; - die_if_no_fixup("Unknown program exception",regs,error_code); - force_sig(SIGSEGV, current); -} - -DO_ERROR(2, SIGILL, "privileged operation", privileged_op, current) -DO_ERROR(3, SIGILL, "execute exception", execute_exception, current) -DO_ERROR(5, SIGSEGV, "addressing exception", addressing_exception, current) -DO_ERROR(9, SIGFPE, "fixpoint divide exception", divide_exception, current) -DO_ERROR(0x12, SIGILL, "translation exception", translation_exception, current) -DO_ERROR(0x13, SIGILL, "special operand exception", special_op_exception, current) -DO_ERROR(0x15, SIGILL, "operand exception", operand_exception, current) - -/* need to define -DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current) -DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current) -DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math) -DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current) -DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current) -DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) -DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current) -DO_ERROR(18, SIGSEGV, "reserved", reserved, current) -DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current) -*/ - -#ifdef CONFIG_IEEEFPU_EMULATION +DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler) +DO_ERROR(SIGILL, "privileged operation", privileged_op) +DO_ERROR(SIGILL, "execute exception", execute_exception) +DO_ERROR(SIGSEGV, "addressing exception", addressing_exception) +DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception) +DO_ERROR(SIGILL, "translation exception", translation_exception) +DO_ERROR(SIGILL, "special operand exception", special_op_exception) +DO_ERROR(SIGILL, "operand exception", operand_exception) -asmlinkage void illegal_op(struct pt_regs * regs, long error_code) +asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; @@ -268,6 +163,7 @@ if(do_debugger_trap(regs,SIGTRAP)) do_sig=1; } +#ifdef CONFIG_IEEEFPU_EMULATION else if (problem_state ) { if (opcode[0] == 0xb3) { @@ -288,18 +184,19 @@ do_sig = math_emu_lfpc(opcode, regs); } else do_sig = 1; - } else - do_sig = 1; - if (do_sig) { - current->thread.error_code = error_code; - current->thread.trap_no = 1; - force_sig(SIGILL, current); - die_if_no_fixup("illegal operation", regs, error_code); } +#endif + else + do_sig = 1; + if (do_sig) + do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL); unlock_kernel(); } -asmlinkage void specification_exception(struct pt_regs * regs, long error_code) + + +#ifdef CONFIG_IEEEFPU_EMULATION +asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; @@ -311,26 +208,26 @@ get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ - math_emu_ldr(opcode); + do_sig=math_emu_ldr(opcode); break; case 0x38: /* LER Rx,Ry */ - math_emu_ler(opcode); + do_sig=math_emu_ler(opcode); break; case 0x60: /* STD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_std(opcode, regs); + do_sig=math_emu_std(opcode, regs); break; case 0x68: /* LD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ld(opcode, regs); + do_sig=math_emu_ld(opcode, regs); break; case 0x70: /* STE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ste(opcode, regs); + do_sig=math_emu_ste(opcode, regs); break; case 0x78: /* LE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_le(opcode, regs); + do_sig=math_emu_le(opcode, regs); break; default: do_sig = 1; @@ -338,47 +235,59 @@ } } else do_sig = 1; - if (do_sig) { - current->thread.error_code = error_code; - current->thread.trap_no = 1; - force_sig(SIGILL, current); - die_if_no_fixup("illegal operation", regs, error_code); - } + if (do_sig) + do_trap(interruption_code, SIGILL, "specification exception", regs, NULL); unlock_kernel(); } +#else +DO_ERROR(SIGILL, "specification exception", specification_exception) +#endif -asmlinkage void data_exception(struct pt_regs * regs, long error_code) +asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; int do_sig = 0; lock_kernel(); - if (regs->psw.mask & 0x00010000L) { - location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + if(MACHINE_HAS_IEEE) + { + __asm__ volatile ("stfpc %0\n\t" + : "=m" (current->thread.fp_regs.fpc)); + } + /* Same code should work when we implement fpu emulation */ + /* provided we call data exception from the fpu emulator */ + if(current->thread.fp_regs.fpc&FPC_DXC_MASK) + { + current->thread.ieee_instruction_pointer=(addr_t)location; + force_sig(SIGFPE, current); + } +#ifdef CONFIG_IEEEFPU_EMULATION + else if (regs->psw.mask & 0x00010000L) { get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ - math_emu_ldr(opcode); + do_sig=math_emu_ldr(opcode); break; case 0x38: /* LER Rx,Ry */ - math_emu_ler(opcode); + do_sig=math_emu_ler(opcode); break; case 0x60: /* STD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_std(opcode, regs); + do_sig=math_emu_std(opcode, regs); break; case 0x68: /* LD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ld(opcode, regs); + do_sig=math_emu_ld(opcode, regs); break; case 0x70: /* STE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ste(opcode, regs); + do_sig=math_emu_ste(opcode, regs); break; case 0x78: /* LE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_le(opcode, regs); + do_sig=math_emu_le(opcode, regs); break; case 0xb3: get_user(*((__u16 *) (opcode+2)), location+1); @@ -406,22 +315,15 @@ do_sig = 1; break; } - } else - do_sig = 1; - if (do_sig) { - current->thread.error_code = error_code; - current->thread.trap_no = 1; - force_sig(SIGILL, current); - die_if_no_fixup("illegal operation", regs, error_code); } +#endif + else + do_sig = 1; + if (do_sig) + do_trap(interruption_code, SIGILL, "data exception", regs, NULL); unlock_kernel(); } -#else -DO_ERROR(1, SIGILL, "illegal operation", illegal_op, current) -DO_ERROR(6, SIGILL, "specification exception", specification_exception, current) -DO_ERROR(7, SIGILL, "data exception", data_exception, current) -#endif /* CONFIG_IEEEFPU_EMULATION */ /* init is done in lowcore.S and head.S */ @@ -463,7 +365,7 @@ /* I've seen this possibly a task structure being reused ? */ printk("Spurious per exception detected\n"); printk("switching off per tracing for this task.\n"); - show_crashed_task_info(); + show_regs(regs); /* Hopefully switching off per tracing will help us survive */ regs->psw.mask &= ~PSW_PER_MASK; } diff -u --recursive --new-file v2.4.1/linux/arch/s390/lib/Makefile linux/arch/s390/lib/Makefile --- v2.4.1/linux/arch/s390/lib/Makefile Fri May 12 11:41:45 2000 +++ linux/arch/s390/lib/Makefile Tue Feb 13 14:13:44 2001 @@ -2,11 +2,17 @@ # Makefile for s390-specific library files.. # +ifdef SMP .S.o: - $(CC) $(AFLAGS) -traditional -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o +else +.S.o: + $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o +endif L_TARGET = lib.a -L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o + +obj-y = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/s390/lib/delay.c linux/arch/s390/lib/delay.c --- v2.4.1/linux/arch/s390/lib/delay.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/lib/delay.c Tue Feb 13 14:13:44 2001 @@ -21,25 +21,30 @@ void __delay(unsigned long loops) { - __asm__ __volatile__( - "0: ahi %0,-1\n" - " jnm 0b" - : /* no outputs */ : "r" (loops) ); + /* + * To end the bloody studid and useless discussion about the + * BogoMips number I took the liberty to define the __delay + * function in a way that that resulting BogoMips number will + * yield the megahertz number of the cpu. The important function + * is udelay and that is done using the tod clock. -- martin. + */ + __asm__ __volatile__( + "0: brct %0,0b" + : /* no outputs */ : "r" (loops/2) ); } -inline void __const_udelay(unsigned long xloops) +/* + * Waits for 'usecs' microseconds using the tod clock + */ +void __udelay(unsigned long usecs) { + uint64_t start_cc, end_cc; - __asm__("LR 3,%1\n\t" - "MR 2,%2\n\t" - "LR %0,2\n\t" - : "=r" (xloops) - : "r" (xloops) , "r" (loops_per_sec) - : "2" , "3"); - __delay(xloops); + if (usecs == 0) + return; + asm volatile ("STCK %0" : "=m" (start_cc)); + do { + asm volatile ("STCK %0" : "=m" (end_cc)); + } while (((end_cc - start_cc)/4096) < usecs); } -void __udelay(unsigned long usecs) -{ - __const_udelay(usecs * 0x000010c6); /* 2**32 / 1000000 */ -} diff -u --recursive --new-file v2.4.1/linux/arch/s390/lib/strcmp.S linux/arch/s390/lib/strcmp.S --- v2.4.1/linux/arch/s390/lib/strcmp.S Fri May 12 11:41:45 2000 +++ linux/arch/s390/lib/strcmp.S Tue Feb 13 14:13:44 2001 @@ -18,8 +18,8 @@ CLST 2,3 JO .-4 JE strcmp_equal - IC 0,0(0,3) - IC 1,0(0,2) + IC 0,0(3) + IC 1,0(2) SR 1,0 strcmp_equal: LR 2,1 diff -u --recursive --new-file v2.4.1/linux/arch/s390/lib/strncpy.S linux/arch/s390/lib/strncpy.S --- v2.4.1/linux/arch/s390/lib/strncpy.S Fri May 12 11:41:45 2000 +++ linux/arch/s390/lib/strncpy.S Tue Feb 13 14:13:44 2001 @@ -20,9 +20,9 @@ SR 0,0 strncpy_loop: ICM 0,1,0(3) # ICM sets the cc, IC does not - LA 3,1(0,3) - STC 0,0(0,1) - LA 1,1(0,1) + LA 3,1(3) + STC 0,0(1) + LA 1,1(1) JZ strncpy_exit # ICM inserted a 0x00 BRCT 4,strncpy_loop # R4 -= 1, jump to strncpy_loop if > 0 strncpy_exit: diff -u --recursive --new-file v2.4.1/linux/arch/s390/lib/uaccess.S linux/arch/s390/lib/uaccess.S --- v2.4.1/linux/arch/s390/lib/uaccess.S Wed Dec 31 16:00:00 1969 +++ linux/arch/s390/lib/uaccess.S Tue Feb 13 14:13:44 2001 @@ -0,0 +1,51 @@ +/* + * arch/s390/lib/uaccess.S + * fixup routines for copy_{from|to}_user functions. + * + * s390 + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * These functions have a non-standard call interface + */ + +#include + + .text + .align 4 + .globl __copy_from_user_fixup +__copy_from_user_fixup: + l 1,__LC_PGM_OLD_PSW+4 + sll 4,1 + srl 4,1 +0: lhi 3,-4096 + sll 3,1 + srl 3,1 + n 3,__LC_TRANS_EXC_ADDR + sr 3,4 + bm 4(1) +1: mvcle 2,4,0 + b 4(1) + .section __ex_table,"a" + .long 1b,0b + .previous + + .align 4 + .text + .globl __copy_to_user_fixup +__copy_to_user_fixup: + l 1,__LC_PGM_OLD_PSW+4 + sll 4,1 + srl 4,1 +0: lhi 5,-4096 + sll 5,1 + srl 5,1 + n 5,__LC_TRANS_EXC_ADDR + sr 5,4 + bm 4(1) +1: mvcle 4,2,0 + b 4(1) + .section __ex_table,"a" + .long 1b,0b + .previous + diff -u --recursive --new-file v2.4.1/linux/arch/s390/mm/Makefile linux/arch/s390/mm/Makefile --- v2.4.1/linux/arch/s390/mm/Makefile Fri May 12 11:41:45 2000 +++ linux/arch/s390/mm/Makefile Tue Feb 13 14:13:44 2001 @@ -8,6 +8,7 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o fault.o ioremap.o extable.o + +obj-y := init.o fault.o ioremap.o extable.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.1/linux/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c --- v2.4.1/linux/arch/s390/mm/fault.c Fri Aug 4 16:15:37 2000 +++ linux/arch/s390/mm/fault.c Tue Feb 13 14:13:44 2001 @@ -9,6 +9,7 @@ * Copyright (C) 1995 Linus Torvalds */ +#include #include #include #include @@ -26,6 +27,10 @@ #include #include +#ifdef CONFIG_SYSCTL +extern int sysctl_userprocess_debug; +#endif + extern void die(const char *,struct pt_regs *,long); /* @@ -48,6 +53,8 @@ int write; unsigned long psw_mask; unsigned long psw_addr; + int si_code = SEGV_MAPERR; + int kernel_address = 0; /* * get psw mask of Program old psw to find out, @@ -65,58 +72,106 @@ address = S390_lowcore.trans_exc_code&0x7ffff000; - if (in_irq()) - die("page fault from irq handler",regs,error_code); - tsk = current; mm = tsk->mm; + if (in_interrupt() || !mm) + goto no_context; + + + /* + * Check which address space the address belongs to + */ + switch (S390_lowcore.trans_exc_code & 3) + { + case 0: /* Primary Segment Table Descriptor */ + kernel_address = 1; + goto no_context; + + case 1: /* STD determined via access register */ + if (S390_lowcore.exc_access_id == 0) + { + kernel_address = 1; + goto no_context; + } + if (regs && S390_lowcore.exc_access_id < NUM_ACRS) + { + if (regs->acrs[S390_lowcore.exc_access_id] == 0) + { + kernel_address = 1; + goto no_context; + } + if (regs->acrs[S390_lowcore.exc_access_id] == 1) + { + /* user space address */ + break; + } + } + die("page fault via unknown access register", regs, error_code); + break; + + case 2: /* Secondary Segment Table Descriptor */ + case 3: /* Home Segment Table Descriptor */ + /* user space address */ + break; + } + + + /* + * When we get here, the fault happened in the current + * task's user address space, so we search the VMAs + */ + down(&mm->mmap_sem); vma = find_vma(mm, address); - if (!vma) { - printk("no vma for address %lX\n",address); + if (!vma) goto bad_area; - } if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) { - printk("VM_GROWSDOWN not set, but address %lX \n",address); - printk("not in vma %p (start %lX end %lX)\n",vma, - vma->vm_start,vma->vm_end); + if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - } - if (expand_stack(vma, address)) { - printk("expand of vma failed address %lX\n",address); - printk("vma %p (start %lX end %lX)\n",vma, - vma->vm_start,vma->vm_end); + 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: write = 0; + si_code = SEGV_ACCERR; + switch (error_code & 0xFF) { case 0x04: /* write, present*/ write = 1; break; case 0x10: /* not present*/ case 0x11: /* not present*/ - if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) { - printk("flags %X of vma for address %lX wrong \n", - vma->vm_flags,address); - printk("vma %p (start %lX end %lX)\n",vma, - vma->vm_start,vma->vm_end); + if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) goto bad_area; - } break; default: printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF); goto bad_area; } - handle_mm_fault(tsk, vma, address, write); + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + switch (handle_mm_fault(mm, vma, address, write)) { + case 1: + tsk->min_flt++; + break; + case 2: + tsk->maj_flt++; + break; + case 0: + goto do_sigbus; + default: + goto out_of_memory; + } up(&mm->mmap_sem); return; @@ -130,19 +185,32 @@ /* User mode accesses just cause a SIGSEGV */ if (psw_mask & PSW_PROBLEM_STATE) { + struct siginfo si; tsk->thread.prot_addr = address; - tsk->thread.error_code = error_code; - tsk->thread.trap_no = 14; - + tsk->thread.trap_no = error_code; +#ifndef CONFIG_SYSCTL +#ifdef CONFIG_PROCESS_DEBUG printk("User process fault: interruption code 0x%lX\n",error_code); printk("failing address: %lX\n",address); - show_crashed_task_info(); - force_sig(SIGSEGV, tsk); + show_regs(regs); +#endif +#else + if (sysctl_userprocess_debug) { + printk("User process fault: interruption code 0x%lX\n", + error_code); + printk("failing address: %lX\n", address); + show_regs(regs); + } +#endif + 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? */ - if ((fixup = search_exception_table(regs->psw.addr)) != 0) { regs->psw.addr = fixup; return; @@ -151,53 +219,47 @@ /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. - * - * First we check if it was the bootup rw-test, though.. */ - if (address < PAGE_SIZE) - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + + if (kernel_address) + printk(KERN_ALERT "Unable to handle kernel pointer dereference" + " at virtual kernel address %08lx\n", address); else - printk(KERN_ALERT "Unable to handle kernel paging request"); - printk(" at virtual address %08lx\n",address); + printk(KERN_ALERT "Unable to handle kernel paging request" + " at virtual user address %08lx\n", address); /* * need to define, which information is useful here */ - lock_kernel(); die("Oops", regs, error_code); do_exit(SIGKILL); - unlock_kernel(); -} -/* - { - char c; - int i,j; - char *addr; - addr = ((char*) psw_addr)-0x20; - for (i=0;i<16;i++) { - if (i == 2) - printk("\n"); - printk ("%08X: ",(unsigned long) addr); - for (j=0;j<4;j++) { - printk("%08X ",*(unsigned long*)addr); - addr += 4; - } - addr -=0x10; - printk(" | "); - for (j=0;j<16;j++) { - printk("%c",(c=*addr++) < 0x20 ? '.' : c ); - } - - printk("\n"); - } - printk("\n"); - } +/* + * 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 (psw_mask & PSW_PROBLEM_STATE) + 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.prot_addr = address; + tsk->thread.trap_no = error_code; + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!(psw_mask & PSW_PROBLEM_STATE)) + goto no_context; +} diff -u --recursive --new-file v2.4.1/linux/arch/s390/mm/init.c linux/arch/s390/mm/init.c --- v2.4.1/linux/arch/s390/mm/init.c Tue Nov 28 22:43:39 2000 +++ linux/arch/s390/mm/init.c Tue Feb 13 14:13:44 2001 @@ -52,10 +52,10 @@ * data and COW. */ -pgd_t swapper_pg_dir[512] __attribute__ ((__aligned__ (4096))); -unsigned long empty_bad_page[1024] __attribute__ ((__aligned__ (4096))); -unsigned long empty_zero_page[1024] __attribute__ ((__aligned__ (4096))); -pte_t empty_bad_pte_table[1024] __attribute__ ((__aligned__ (4096))); +pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); +char empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); +char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); +pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE))); static int test_access(unsigned long loc) { @@ -104,47 +104,6 @@ pte_clear(pte++); } -void __handle_bad_pmd(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); -} - -void __handle_bad_pmd_kernel(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - invalidate_page(pte); - pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(pte); - pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(pte)+1024; - pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(pte)+2048; - pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(pte)+3072; - return pte + offset; - } - pte = get_bad_pte_table(); - pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(pte); - pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(pte)+1024; - pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(pte)+2048; - pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(pte)+3072; - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) { unsigned long pte; @@ -167,10 +126,8 @@ return NULL; } free_page(pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } + if (pmd_bad(*pmd)) + BUG(); return (pte_t *) pmd_page(*pmd) + offset; } @@ -180,7 +137,7 @@ if(pgtable_cache_size > high) { do { if(pgd_quicklist) - free_pgd_slow(get_pgd_fast()), freed++; + free_pgd_slow(get_pgd_fast()), freed += 2; if(pmd_quicklist) free_pmd_slow(get_pmd_fast()), freed++; if(pte_quicklist) @@ -245,6 +202,7 @@ unsigned long address=0; unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; unsigned long end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE); + static const int ssm_mask = 0x04000000L; /* unmap whole virtual address space */ @@ -283,8 +241,9 @@ /* enable virtual mapping in kernel mode */ __asm__ __volatile__(" LCTL 1,1,%0\n" " LCTL 7,7,%0\n" - " LCTL 13,13,%0" - : :"m" (pgdir_k)); + " LCTL 13,13,%0\n" + " SSM %1" + : : "m" (pgdir_k), "m" (ssm_mask)); local_flush_tlb(); @@ -378,6 +337,7 @@ val->sharedram = 0; val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = 0; + val->freehigh = 0; val->mem_unit = PAGE_SIZE; - return; } diff -u --recursive --new-file v2.4.1/linux/arch/s390/mm/ioremap.c linux/arch/s390/mm/ioremap.c --- v2.4.1/linux/arch/s390/mm/ioremap.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/mm/ioremap.c Tue Feb 13 14:13:44 2001 @@ -33,8 +33,8 @@ printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | - _PAGE_DIRTY | _PAGE_ACCESSED | flags))); + set_pte(pte, mk_pte_phys(phys_addr, + __pgprot(_PAGE_PRESENT | flags))); address += PAGE_SIZE; phys_addr += PAGE_SIZE; pte++; diff -u --recursive --new-file v2.4.1/linux/arch/s390/tools/dasdfmt/Makefile linux/arch/s390/tools/dasdfmt/Makefile --- v2.4.1/linux/arch/s390/tools/dasdfmt/Makefile Fri May 12 11:41:45 2000 +++ linux/arch/s390/tools/dasdfmt/Makefile Tue Feb 13 14:13:44 2001 @@ -1,7 +1,7 @@ all: dasdfmt dasdfmt: dasdfmt.c - $(CROSS_COMPILE)gcc -o $@ $^ + $(CC) -o $@ $^ $(STRIP) $@ clean: diff -u --recursive --new-file v2.4.1/linux/arch/s390/tools/dasdfmt/dasdfmt.8 linux/arch/s390/tools/dasdfmt/dasdfmt.8 --- v2.4.1/linux/arch/s390/tools/dasdfmt/dasdfmt.8 Fri May 12 11:41:45 2000 +++ linux/arch/s390/tools/dasdfmt/dasdfmt.8 Fri Feb 16 16:02:34 2001 @@ -3,8 +3,7 @@ .SH NAME dasdfmt \- formatting of DSAD (ECKD) disk drives. .SH SYNOPSIS -\fBdasdfmt\fR [-tvyV] [-b \fIblockSize\fR] [\fIblockRange\fI] - \fIdiskSpec\fR +\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR .SH DESCRIPTION \fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of @@ -25,6 +24,10 @@ Start formatting without further user-confirmation. .TP +\fB-L\fR +Omit the writing of a disk label after formatting. + +.TP \fB-V\fR Print version number and exit. @@ -35,26 +38,17 @@ it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR. .TP -\fIblockRange\fR -This parameter specifies the number of the first and last block to be -formatted. If this parameter is \fBomitted\fR, formatting the \fBwhole\fR disk -is assumed. The \fIblockRange\fR can be specified in two different formats: -.sp - \fB-s\fR \fIstartBlock\fR \fB-e\fR \fIendBlock\fR -.br -or -.br - \fB-r\fR \fIstartBlock\fR-\fIendBlock\fR -.sp -If \fIstartBlock\fR is omitted, block \fB0\fR is assumed. If -\fIendBlock\fR is omitted, the last block of the disk is assumed. +\fB-l\fR \fIdiskLabel\fR +Specify the label to be written to disk after formatting. If no label is +specified, a sensible default is used. \fIdiskLabel\fR is interpreted as +ASCII string and is automatically converted to EBCDIC. .TP \fIdiskSpec\fR This parameter specified the device to be formatted. It also can be given in two variants: .sp - \fB-f\fR \fB/dev/dd\fR\fIX\fR + \fB-f\fR \fB/dev/dasd\fR\fIX\fR .br or .br @@ -63,7 +57,7 @@ The first form uses the commonly used .SM UNIX device notation where \fIX\fR is a single lowercase letter. -The second form uses simply the VM vdev number. +The second form uses simply the device number. .SH BUGS None so far ;-) diff -u --recursive --new-file v2.4.1/linux/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c --- v2.4.1/linux/arch/s390/tools/dasdfmt/dasdfmt.c Fri May 12 11:41:45 2000 +++ linux/arch/s390/tools/dasdfmt/dasdfmt.c Tue Feb 13 14:13:44 2001 @@ -12,6 +12,8 @@ * detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them */ +/* #define _LINUX_BLKDEV_H */ + #include #include #include @@ -25,19 +27,25 @@ #include #include #include -#include "../../../drivers/s390/block/dasd.h" /* uses DASD_PARTN_BITS */ #define __KERNEL__ /* we want to use kdev_t and not have to define it */ #include #undef __KERNEL__ +#include +#include +#include + #define EXIT_MISUSE 1 #define EXIT_BUSY 2 #define TEMPFILENAME "/tmp/ddfXXXXXX" #define TEMPFILENAMECHARS 8 /* 8 characters are fixed in all temp filenames */ -#define IOCTL_COMMAND 'D' << 8 #define SLASHDEV "/dev/" #define PROC_DASD_DEVICES "/proc/dasd/devices" +/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */ +#define PROC_MOUNTS _PATH_MOUNTED +#define PROC_SWAPS "/proc/swaps" #define DASD_DRIVER_NAME "dasd" +#define LABEL_LENGTH 10 #define PROC_LINE_LENGTH 80 #define ERR_LENGTH 80 @@ -66,24 +74,108 @@ ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \ "is in invalid format\n",prog_name);} -typedef struct { - int start_unit; - int stop_unit; - int blksize; -} format_data_t; - -char prog_name[]="dasd_format"; +char *prog_name;/*="dasdfmt";*/ char tempfilename[]=TEMPFILENAME; +__u8 _ascebc[256] = +{ + /*00 NUL SOH STX ETX EOT ENQ ACK BEL */ + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + /*08 BS HT LF VT FF CR SO SI */ + /* ->NL */ + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + /*18 CAN EM SUB ESC FS GS RS US */ + /* ->IGS ->IRS ->IUS */ + 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, + /*20 SP ! " # $ % & ' */ + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + /*28 ( ) * + , - . / */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + /*30 0 1 2 3 4 5 6 7 */ + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + /*38 8 9 : ; < = > ? */ + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + /*40 @ A B C D E F G */ + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + /*48 H I J K L M N O */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + /*50 P Q R S T U V W */ + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + /*58 X Y Z [ \ ] ^ _ */ + 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, + /*60 ` a b c d e f g */ + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + /*68 h i j k l m n o */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + /*70 p q r s t u v w */ + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + /*78 x y z { | } ~ DL */ + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + /*80*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*88*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*90*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*98*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*A0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*A8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*B0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*B8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*C0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*C8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*D0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*D8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*E0 sz */ + 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*E8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*F0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*F8*/ + 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF +}; + +void convert_label(char *str) +{ + int i; + for (i=0;i \n\n", - prog_name); - printf(" where is either\n"); - printf(" -s start_track -e end_track\n"); +#ifdef RANGE_FORMATTING + printf("Usage: %s [-htvyLV] [-l